我在linux系统上遇到过socket通信的问题,通信过程如下:客户端发送消息请求服务器做计算任务,任务完成后等待服务器的结果消息。
但是如果任务花费了很长时间,比如大约 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());
}
所以有谁知道我应该做些什么来解决这个问题。我猜是环境设置的原因,但不知道是什么环境因素会影响socket通信?
而socket使用Tcp/Ip协议进行通信,问题与任务时间长有关,那么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 Timed out 异常呢?