原因:java.net.SocketException:连接超时,不是SocketTimeoutException

时间:2012-01-18 02:41:37

标签: sockets objectinputstream

这个SocketException是在ObjectInputStream.readObject()方法中抛出的,是什么导致这种情况?此外,客户端和服务器套接字的soTimeout值均为0,KeepAlive值为false。

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

从有关setSoTimeout方法的JAVA API文档中,如果此方法设置为非零值,则当时间到期时,仅抛出SocketTimeoutException,而不是SocketException:Connection超时,因此,此异常不应关联使用setSotimeoutMethod。

public void setSoTimeout(int timeout)  throws SocketException
 Enable/disable SO_TIMEOUT with the specified timeout, in milliseconds. With this 
 option set to a non-zero timeout, a read() call on the InputStream associated with 
 this Socket will block for only this amount of time. If the timeout expires, a 
 java.net.SocketTimeoutException is raised, though the Socket is still valid. The 
option must be enabled prior to entering the blocking operation to have effect. The 
timeout must be > 0. A timeout of zero is interpreted as an infinite timeout.

但是,PlainSocketImpl返回的值(此处为SSLSocketImpl).getTimeout()由setSoTimeout()方法传递,那么它仍然是一种非常奇怪的方法。

 SocketInputStream.socketRead0(FileDescriptor fd, byte b[], int off, int len, int timeout)  
  the timeout value is passed in the constructor of  SocketInputStream:SocketInputStream(PlainSocketImpl impl) throws IOException {}
  timeout = impl.getTimeout();

1 个答案:

答案 0 :(得分:5)

java.net.SocketException:Connection超时异常与setTimeout方法无关,后者只与SocketTimedoutException有关。

从tcpdump捕获的消息跟踪中,如下所示:

NO.            Time       Source Destination Protocol Info
14845 2012-02-07 22:37:46 10.*   10.*        DNP 3. len=1,from 52156 to 29466,ACK 
14846 2012-02-07 22:37:46 21.*   10.*        DNP 3. len=1,from 54562 to 50276,ACK
14848 2012-02-07 22:37:46 32.*   10.*        DNP 3. [TCP Restransmission] len=1,from from 52156 to 29466,ACK 
……(7 times retransmission) 
14849 2012-02-07 22:37:47 10.*   10.*        DNP 3. [TCP Restransmission] len=1,from from 52156 to 29466,ACK

这个日志抛出java.net.SocketException:连接在22:54超时,距离调用的writeObject大约15分钟。

因此我们可以得出结论,这个异常是由于tcp连接可能因为很长时间(大约30分钟)没有流量而无法使用,同时没有调用socket.close()方法来关闭套接字例如,抛出了这个异常。

所以为了避免这个异常,你应该使用方法Socket.setKeepAlive()方法使连接保持活动状态,尽管你可能还没有使用方法setTimeout(),这意味着要求套接字无限制地接收;

或者在您的应用程序中应用心跳机制。