ObjectInputStream.readObject()在套接字通信过程中永久挂起

时间:2012-01-10 05:33:02

标签: java linux sockets objectoutputstream objectinputstream

我在linux系统上遇到套接字通信问题,通信过程如下:客户端发送消息要求服务器执行计算任务,并在任务完成后等待服务器的结果消息。 / p>

但是,如果任务花费很长时间,例如大约40分钟,客户端会挂起等待结果消息,即使从服务器端,结果消息已写入套接字以响应客户端,但是如果任务花费很少的时间,例如一分钟,它通常可以收到结果消息。此外,此问题仅发生在客户环境中,通信过程在我们的测试环境中正常运行。

我怀疑这个问题的原因是套接字的默认超时值在客户环境和测试环境之间是不同的,但是这两个环境以及客户端和服务器的跟随值是相同的。

getSoTimeout:0
getReceiveBufferSize:43690
getSendBufferSize:8192
getSoLinger:-1
getTrafficClass:0
getKeepAlive:false
getTcpNoDelay:false

CLient上的代码如下:

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 protocal进行通信,问题与长时间任务有关,那么关于tcp的什么值会影响socket通信的超时?

在我对日志的分析之后,我发现在将消息写入套接字之后,没有抛出/捕获异常。但总是在15分钟后,服务器端的objectInputStream.readObject()代码片段中有异常,用于接受来自客户端的请求。但是,socket.getSoTimeout值为0,因此抛出Timed out Exception非常奇怪。

{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)

那么为什么会抛出Connection超时异常呢?

2 个答案:

答案 0 :(得分:2)

此问题已解决。使用tcpdump捕获消息流。我发现在应用程序级别调用ObjectOutputStream.writeObject()方法时,在tcp级别中,多次找到[TCP ReTransmission]

所以,我断定连接可能已经死了,尽管使用netstat -an命令,tcp连接状态仍然是ESTABLISHED

因此,我编写了一个测试应用程序,定期发送测试消息作为来自服务器的令人心碎的消息。然后这个问题就消失了。

答案 1 :(得分:1)

read()的{​​{1}}方法是阻止来电。这意味着他们会等待"永远"如果在要读取的流中没有数据时调用它们。

如果服务器没有响应,这是完全预期的行为,并且根据javadoc中发布的合同。

如果您想要非阻塞读取,请使用java.io.InputStream类。