I'm using the Java NIO API for socket communication (in blocking mode).
I noticed that when the remote host closes the connection, my client doesn't notice it - the client can still send data and doesn't get an exception, as if the data has been sent successfully. Have a look at the code below, which does the following: Start a very simple server, which accepts a connection and closes it after a short delay of 200ms. The client opens a connection, which the server accepts. Before sending data, the client waits one second, so that the server has closed the connection in the meantime. Then the client sends some data.
I would expect that an exception would happen in the client when trying to send the data, because the server has already closed the connection. However, this doesn't happen. Why not, and how can I detect if the connection is still open and can be used to send data? Calling channel.isConnected() doesn't work - it will return true even after the server has already closed the connection.
Server accepted client connection
Server closed connection
Client sent 4 bytes
Client closed connection
I've found out myself why this happens. It has to do with how TCP/IP works.
TCP/IP is a connection-oriented protocol: you make a connection, then you can send and receive data, and at the end you close the connection. However, TCP is built on top of IP, which is a packet-oriented protocol. Some of this shows through the TCP protocol (it's a leaky abstraction - you're not supposed to be bothered with how TCP is implemented under the covers, but inevitably you have to deal with some of the implementation details anyway).
So, when the remote system closes the connection, the client might not notice it immediately, and it seems like you can still send data to the remote system. It will take a while before the client notices that no acknowledgements are received anymore.
One way to solve this is to define a disconnect message at the application-level protocol; in other words, the remote host should send the client a "I'm going to close the connection now!" message before really closing it.
I am digging out a rather old post, but it perfectly describes my question. My problem with the above setup is: The sending side only seems to recognize the dropped connection, if I send more data than I actually intend to (probably one has to send more than fits in the sockets send buffer). So my question is: can I safely detect if a connection has been dropped without an extra acknowledge mechanism?