更新我发现这个错误与 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 上发生。我不认为这会是原因,但只是想我应该提一下。
任何帮助都非常感谢,因为我对这里问题的原因感到迷茫。