java - ObjectInputStream.readObject()在socket通信过程中永远挂起

标签 java linux sockets objectoutputstream objectinputstream

我在linux系统上遇到过一个socket通信的问题,通信过程是这样的:client发消息要求server做一个计算任务,任务完成后等待server返回result消息。

但是如果任务耗时较长,比如40分钟左右,客户端就会挂起等待结果消息,即使从服务器端,结果消息已经写入socket响应客户端,但是如果任务花费的时间很短,例如一分钟,它通常可以收到结果消息。此外,此问题仅发生在客户环境中,通信过程在我们的测试环境中表现正常。

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

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());
 }

所以有谁知道我下一步应该做什么来解决这个问题。 我猜是环境设置的原因,但我不知道环境因素会影响套接字通信?

而使用Tcp/Ip协议(protocol)通信的socket,问题是与长时间任务有关,那么tcp取什么值会影响socket通信的超时呢?

经过我对日志的分析,我发现在将消息写入套接字后,没有抛出/捕获异常。但总是在15分钟后,用于接受客户端请求的Server Side的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 Timed out 异常呢?

最佳答案

这个问题解决了。使用 tcpdump 捕获消息流。我发现在应用程序级别,ObjectOutputStream.writeObject() 方法被调用,而在 tcp 级别,多次发现 [TCP ReTransmission]

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

所以我写了一个测试应用程序来定期从服务器发送测试消息作为心跳消息。然后这个问题就消失了。

关于java - ObjectInputStream.readObject()在socket通信过程中永远挂起,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8798985/

相关文章:

java - Apache kafka - 从java应用程序打印到控制台

java - 为什么枚举可以有包私有(private)构造函数?

linux - Pathos:在 Linux 上强制生成

c - 使用 fprintf 发送方向键

java - 类 ClassFormatError :Absent-Code-attribute-in-method-that-is-not-native

-std=c99 可以阻止我的#includes 正常工作吗?

c - 查找UDP数据包的源IP/进程

iOS 使用套接字与其他应用程序通信

c - 使用 libnl-3 发送 Netlink Taskstats 消息

java - 如何在不破坏当前设置的情况下安装多个版本的JDK?