Java ObjectInputStream.readObject()在套接字通信过程中永远挂起
我在linux系统上遇到了一个套接字通信问题,通信过程如下:客户端发送消息要求服务器执行计算任务,并在任务完成后等待来自服务器的结果消息 但是,如果任务花费很长时间(例如大约40分钟),客户机将挂起等待结果消息,即使从服务器端,结果消息已写入套接字以响应客户机,但是如果任务花费很少的时间(例如一分钟),客户机通常可以接收结果消息。此外,此问题仅发生在客户环境中,通信过程在我们的测试环境中正常运行 我怀疑导致此问题的原因是客户环境和测试环境之间套接字的默认超时值不同,但以下值在这两个环境以及客户端和服务器上是相同的Java ObjectInputStream.readObject()在套接字通信过程中永远挂起,java,linux,sockets,objectoutputstream,objectinputstream,Java,Linux,Sockets,Objectoutputstream,Objectinputstream,我在linux系统上遇到了一个套接字通信问题,通信过程如下:客户端发送消息要求服务器执行计算任务,并在任务完成后等待来自服务器的结果消息 但是,如果任务花费很长时间(例如大约40分钟),客户机将挂起等待结果消息,即使从服务器端,结果消息已写入套接字以响应客户机,但是如果任务花费很少的时间(例如一分钟),客户机通常可以接收结果消息。此外,此问题仅发生在客户环境中,通信过程在我们的测试环境中正常运行 我怀疑导致此问题的原因是客户环境和测试环境之间套接字的默认超时值不同,但以下值在这两个环境以及客户端
getSoTimeout:0
getReceiveBufferSize:43690
getSendBufferSize:8192
getSoLinger:-1
getTrafficClass:0
getKeepAlive:false
getTcpNoDelay:false
客户端上的代码如下所示:
Message msg = null;
ObjectInputStream in = client.getClient().getInputStream();
//if no message readObject() will hang here
while ( true ) {
try {
Object recObject = in.readObject();
System.out.println("Client received msg.");
msg = (Message)recObject;
return msg;
}catch (Exception e) {
e.printStackTrace();
return null;
}
}
服务器上的代码如下:
ObjectOutputStream socketOutStream = getSocketOutputStream();
try {
MessageJobComplete msgJobComplete = new MessageJobComplete(reportFile, outputFile );
socketOutStream.writeObject(msgJobComplete);
}catch(Exception e) {
e.printStackTrace();
}
为了解决这个问题,我增加了flush和reset方法,但是问题仍然存在:
ObjectOutputStream socketOutStream = getSocketOutputStream();
try {
MessageJobComplete msgJobComplete = new MessageJobComplete(reportFile, outputFile );
socketOutStream.flush();
logger.debug("AbstractJob#reply to the socket");
socketOutStream.writeObject(msgJobComplete);
socketOutStream.reset();
socketOutStream.flush();
logger.debug("AbstractJob#after Flush Reply");
}catch(Exception e) {
e.printStackTrace();
logger.error("Exception when sending MessageJobComplete."+e.getMessage());
}
那么,有人知道我下一步应该做什么来解决这个问题吗。
我猜原因是环境设置,但我不知道哪些环境因素会影响套接字通信
而socket使用Tcp/Ip协议进行通信,问题与长时间任务有关,那么Tcp的哪些值会影响socket通信的超时
在对日志进行分析之后,我发现在消息写入套接字之后,没有抛出/捕获异常。但通常在15分钟后,服务器端的objectInputStream.readObject()代码片段中会出现异常,用于接受客户端的请求。但是,socket.getSoTimeout值为0,因此引发超时异常非常奇怪
{2012-01-09 17:44:13,908} ERROR java.net.SocketException: Connection timed out
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:146)
at sun.security.ssl.InputRecord.readFully(InputRecord.java:312)
at sun.security.ssl.InputRecord.read(InputRecord.java:350)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:809)
at sun.security.ssl.SSLSocketImpl.readDataRecord(SSLSocketImpl.java:766)
at sun.security.ssl.AppInputStream.read(AppInputStream.java:94)
at sun.security.ssl.AppInputStream.read(AppInputStream.java:69)
at java.io.ObjectInputStream$PeekInputStream.peek(ObjectInputStream.java:2265)
at java.io.ObjectInputStream$BlockDataInputStream.peek(ObjectInputStream.java:2558)
at java.io.ObjectInputStream$BlockDataInputStream.peekByte(ObjectInputStream.java:2568)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1314)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:368)
那么,为什么会引发连接超时异常呢 java.io.InputStream的read()
方法正在阻止调用,这意味着如果在流中没有数据可读取时调用它们,它们将“永远”等待
如果服务器没有响应,这完全是预期的行为,并且符合javadoc中发布的合同
如果需要非阻塞读取,请使用
java.nio.*
类。此问题已解决。使用tcpdump
捕获消息流。我发现在应用程序级别调用了ObjectOutputStream.writeObject()
方法,而在tcp级别,多次发现了[tcp重新传输]
因此,我得出结论,连接可能已断开,尽管使用netstat-an
命令,tcp连接状态仍然是已建立的
因此,我编写了一个测试应用程序,定期从服务器发送测试消息作为心跳消息。然后这个问题就消失了 感谢您的响应,但实际上服务器已经将对象写入套接字以响应客户端。所以我不知道为什么客户端不能接收。如果客户端没有接收,很可能是服务器没有发送。我想确认您看到了客户端未接收到的已发送对象的日志消息。如果客户端未接收,则可能是服务器未发送。我确认您看到了客户端未收到的已发送对象的日志消息。谢谢,但日志显示该对象已发送,并且未检测到任何异常,只是客户端挂起,您知道如何检查吗?{2012-01-09 19:28:16416}调试抽象作业#回复套接字{2012-01-09 19:28:16422}调试抽象作业#刷新回复后printStackTrace不会出现在日志中,而是写入控制台。如果您没有将控制台写入文件,我会确保将异常写入日志。当抛出异常时,官方代码包含日志操作,并且此处没有记录错误,但是,在将对象写入套接字后,ObjectInputStream.readObject()会抛出异常在等待客户端请求的服务器端,请查看我修改的帖子。