0

更新我发现这个错误与 GZIP 流有关。如果我删除它们并只使用对象流而不是用对象流包装的 GZIP,那么我的问题就解决了,没有例外。我不知道为什么会这样,如果有人可以提供帮助,那就太好了。

我还注意到,在使用 GZIP 时,错误是非常随机的。例如,它似乎很大程度上取决于我通过套接字发送的对象中的数据。更改对象数据,有时可以解决问题。例如,我有一个包含字符串值的用户对象,例如名字、姓氏、电话号码。如果它们都设置好了,我会遇到以下问题,但是如果我将它们全部清除为空字符串值,那么我不会得到以下异常。老实说这很奇怪

我有一个客户端/服务器套接字,它通过 GZIP 流发送对象。这在过去没有问题。但是,现在我在将某些数据从服务器发送回客户端时看到连接重置。

客户端连接到服务器并发送请求,服务器将回复并发送回一些数据。我相信错误来自服务器,因为连接重置异常出现在客户端。

这是异常的片段

java.net.SocketException: Connection reset
at java.net.SocketInputStream.read(SocketInputStream.java:168)
at com.sun.net.ssl.internal.ssl.InputRecord.readFully(InputRecord.java:293)
at com.sun.net.ssl.internal.ssl.InputRecord.read(InputRecord.java:331)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:863)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readDataRecord(SSLSocketImpl.java:820)
at com.sun.net.ssl.internal.ssl.AppInputStream.read(AppInputStream.java:75)

这是一个非常奇怪的问题,因为所有客户端/服务器通信都使用相同的套接字实现,并且在我们的测试环境中一切正常。当客户端在启动时加载应用程序时,在异常发生之前从服务器收集一些数据也成功使用了相同的代码。

上述信息使我相信正在传递的特定数据可能存在问题,尽管客户端和服务器除了连接重置之外都没有异常。

在调试时查看 netstat ( netstat -anp ),我可以看到成功的操作导致套接字处于“CLOSE_WAIT”状态,但是不成功的操作套接字似乎一起消失了,它在任何状态下都不存在。我还注意到,连接完成时会有很多 RST,即使在我没有收到连接重置异常的成功情况下也是如此。我的 TCP 知识不是很好,但我原以为干净的连接会以 FIN 结束而不是 RST?

这是代码示例

客户:

ObjectOutputStream out = null;
ObjectInputStream ois = null;

SSLSocketFactory sf = AdminClientApplet.getSSLContext().getSocketFactory();
Socket socket = null;

DataResponse dataRes = null;

try
{
    socket = sf.createSocket( server.getHost(), server.getPort() );

    // Need to connect to server and send request type,
    // ie what we are requesting to be sent to us
    GZIPOutputStream gZipOut = new GZIPOutputStream(socket.getOutputStream());
    out = new ObjectOutputStream(gZipOut);

    // write our request
    out.writeObject( dataReq );
    out.flush();
    gZipOut.finish();

    InputStream in = socket.getInputStream();
    GZIPInputStream gZipIn = new GZIPInputStream(in, 65536);
    ois = new ObjectInputStream(gZipIn);

    // read our response
    dataRes = ( DataResponse )ois.readObject();
    Log.CSSO.debug("Read object " + dataRes );
}
catch (IOException ie)
{
    Log.GUIP.error("IOException communicating with Admin Server on "+server, ie);
}
catch ( Exception e)
{
    Log.GUIP.error("Unexpected exception communicating with Admin Server on "+server, e);
}        
catch (Throwable t)
{
    Log.GUIP.error("Unexpected exception communicating with Admin Server on "+server, t);
}
finally
{
    // now close the connection gracefully
    CSSO.debug("closing socket");

    try
    {
        if ( out != null )
            out.close();

        if ( ois != null )
            ois.close();

        if ( socket != null )
            socket.close();
    }
    catch ( Exception e )
    {
        Log.CSSO.error( "Error closing socket connection during getDataFromServer()", e );
    }
}

服务器此时已经读取了“请求”,因此这只是将请求的数据返回给客户端的部分。服务器:

Socket socket = null;

try
{
    socket = request.getSocket();
    socket.setTcpNoDelay(true);

    Log.CSSO.debug("Opening a response output stream to socket "+socket );

    gZipOut = new GZIPOutputStream(socket.getOutputStream(), 65536 );
    out = new ObjectOutputStream(gZipOut);

    // the actual 'data' we are going to return
    obj = getObject();

    Log.CSSO.debug("About to write " + obj + " to socket" + socket.getRemoteSocketAddress() );

    out.writeObject( obj );

    if (Log.CSSO.isDebugEnabled())
    {
        Log.CSSO.debug("Wrote DataResponse to socket " + obj );
    }

    out.flush();
    gZipOut.finish();
}
catch (IOException ie)
{
    Log.CSSO.error("IOException caught sending data to client", ie);
}
catch (Exception e)
{
    Log.CSSO.error("Unexpected exception caught sending data to client", e);
}
finally
{
    Log.CSSO.debug( "Closing socket to " + socket.getRemoteSocketAddress() );
    try
    {
        if ( out != null ) out.close();
        if ( socket != null ) socket.close();
    }    
    catch ( IOException e ) 
    {
    Log.CSSO.error("Unexpected exception caught closing socket", e );
    }
}

Log.FLOW.debug("< run");

在调试日志记录时,服务器一直运行到完成,没有任何异常(因此“<运行”写入日志)。但是客户端错误

ois = new ObjectInputStream(gZipIn);

另一个值得注意的项目是发生异常的实时系统正在运行 linux ( Centos ),因为我无法在 Windows 上复制异常,并且它也不会在 Linux Mint 上发生。我不认为这会是原因,但只是想我应该提一下。

任何帮助都非常感谢,因为我对这里问题的原因感到迷茫。

4

0 回答 0