开发者

Java socket not throwing exceptions on a dead socket?

We have a simple client server architecture between our mobile device and our server both written in Java. An extremely simple ServerSocket and Socket implementation. However one problem is that when the client terminates abruptly (without closing the socket properly) the server does not know that it is disconnected. Furthermore, the server can continue开发者_运维问答 to write to this socket without getting any exceptions. Why?

According to documentation Java sockets should throw exceptions if you try to write to a socket that is not reachable on the other end!


The connection will eventually be timed out by Retransmit Timeout (RTO). However, the RTO is calculated using a complicated algorithm based on network latency (RTT), see this RFC,

http://www.ietf.org/rfc/rfc2988.txt

So on a mobile network, this can be minutes. Wait 10 minutes to see if you can get a timeout.

The solution to this kind of problem is to add a heart-beat in your own application protocol and tear down connection when you don't get ACK for the heartbeat.


The key word here (without closing the socket properly).

Sockets should always be acquired and disposed of in this way:

final Socket socket = ...; // connect code

try
{
    use( socket ); // use socket
}
finally
{
    socket.close( ); // dispose
}

Even with this precautions you should specify application timeouts, specific to your protocol.

My experience had shown, that unfortunately you cannot use any of the Socket timeout functionality reliably ( e.g. there is no timeout for write operations and even read operations may, sometimes, hang forever ).

That's why you need a watchdog thread that enforces your application timeouts and disposes of sockets that have been unresponsive for a while.

One convenient way of doing this is by initializing Socket and ServerSocket through corresponding channels in java.nio. The main advantage of such sockets is that they are Interruptible, that way you can simply interrupt the thread that does socket protocol and be sure that socket is properly disposed off.

Notice that you should enforce application timeouts on both sides, as it is only a matter of time and bad luck when you may experience unresponsive sockets.


TCP/IP communications can be very strange. TCP will retry for quite a while at the bottom layers of the stack without ever letting the upper layers know that anything happened.

I would fully expect that after some time period (30 seconds to a few minutes) you should see an error, but I haven't tested this I'm just going off how TCP apps tend to work.

You might be able to tighten the TCP specs (retry, timeout, etc) but again, haven't messed with it much.

Also, it may be that I'm totally wrong and the implementation of Java you are using is just flaky.


To answer the first part of the question (about not knowing that the client has disconnected abruptly), in TCP, you can't know whether a connection has ended until you try to use it.

The notion of guaranteed delivery in TCP is quite subtle: delivery isn't actually guaranteed to the application at the other end (it depends on what guaranteed means really). Section 2.6 of RFC 793 (TCP) gives more details on this topic. This thread on the Restlet-discuss list and this thread on the Linux kernel list might also be of interest.

For the second part (not detecting when you write to this socket), this is probably a question of buffer and timeout (as others have already suggested).


I am facing the same problem. I think when you register the socket with a selector it doesn't throw any exception. Are you using a selector with your socket?

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜