JAVA : Handling socket disconnection
Asked Answered
A

4

1
  1. Two computers are connected by socket connection. If the server/client closes the connection from their end(i.e closes the InputStream, OutputStream and Socket) then how can I inform the other end about the disconnection? There is one way I know of - trying to read from the InputStream, which throws an IOException if connection is closed, but is there any other way to detect this?
  2. Another question, I looked the problem up on the internet and saw inputStream.available() does not solve this problem. Why is that?

Additional Information : I'm asking for another way because my project becomes tough to handle if I have to try to read from the InputStrem to detect a disconnection.

Aprilaprile answered 3/9, 2012 at 7:39 Comment(4)
Um, not sure how else you expect to solve this. You will still need some kind of socket read or write to determine that it was closed.Jadeite
Thinking how u can do this so that their is an instant notification when the other side closes (properly closes, not just disconnects) its Socket: 1) A thread dedicated to reading the socket and putting the data into a container for future processing, ex. ArrayBlockingQueue. When it finds -1 or IOException then it can stop and notify other threads that the communications have ended (or been interupted) by setting a flag, calling some method, or putting an EOS marker in the queue. 2) The other thread(s) can read the queue when they want, and also check the flag when they want.Mielke
@SaintHill Allthat adds precisely nothing to doing the reading yourself.Rilda
@EJP True. It's just an alternate method of doing the inevitable :)Mielke
R
7

trying to read from the InputStream, which throws an IOException

That is not correct. If the peer closes the socket:

  • read() returns -1
  • readLine() returns null
  • readXXX() throws EOFException, for any other X.

As InputStream only has read() methods, it only returns -1: it doesn't throw an IOException at EOS.

Contrary to other answers here, there is no TCP API or Socket method that will tell you whether the peer has closed the connection. You have to try a read or a write.

You should use a read timeout.

InputStream.available() doesn't solve the problem because it doesn't return an EOS indication of any kind. There are few correct uses of it, and this isn't one of them.

Rilda answered 3/9, 2012 at 8:18 Comment(0)
M
0

The problem is not "if the server/client closes the connection". The problem is "what if they do not close the connection and yet the connection is broken?"

There is no way to detect that without a heartbeat protocol of your own.

Another option is to set SO_KEEPALIVE to true.

"When the keepalive option is set for a TCP socket and no data has been exchanged across the socket in either direction for 2 hours (NOTE: the actual value is implementation dependent)"

In my experience, it is much sooner than every 2 hours. More like a ~5 minutes. Other than using So_KEEPALIVE, you are royally screwed :P

In my communications protocols, I use a reserved 'heartbeat' byte that is sent every 2 seconds. My own filterInputStream and filterOutputStream sends/and digests the heartbeat byte.

Mielke answered 3/9, 2012 at 7:55 Comment(3)
Man I laughed at your answer :DAprilaprile
Setting SO_KEEPALIVE does nothing unless you do a read or a write, and if the peer closes the connection it does nothing at all. It's not an EOS test, it's a way for interrupted idle connections to be detected.Rilda
No, i got that, I laughed at the part "you are royally screwed :P"Aprilaprile
P
0

There is no O-O-O way to get a callback/exception the moment the connection is broken. You only get to know about the broken connection only when you do a explicit read/write on the socket stream.

There are two ways to read from a socket viz. Synchronously read byte by byte as they arrive; or wait untill a desired number of bytes available on the stream and then do a bulk read. You do the check by calling available() on the socket stream which gives you the number of bytes currently available for read. In the second case, if the socket connection is broken for some reason there is no way you can be notified of that. In that case you need to employ a timeout mechanism for your wait. In the first case where you do explicit read/write you get an exception.

Pipette answered 3/9, 2012 at 7:58 Comment(1)
O-O-O has nothing to do with it. There is no way at all. The technique of calling available() has nothing to recommend it. It's just a more complex and more error-prone way of blocking in a loop.Rilda
S
0

Q1 If you close the socket connection on server, the client should throw an exception if not immediately, certainly on the next read attempt, and visa versa.

Q2 From the JavaDocs

Returns an estimate of the number of bytes that can be read (or skipped over) from this input stream without blocking by the next invocation of a method for this input stream. The next invocation might be the same thread or another thread. A single read or skip of this many bytes will not block, but may read or skip fewer bytes.

This is not an indication of the number of bytes currently in the stream, but an estimate of the number of bytes that may be read from the implementation that won't block the current thread

Staghound answered 3/9, 2012 at 7:59 Comment(4)
Socket.isClosed() doesn't tell you whether the peer has closed his end of the connection. It tells you whether you have closed that Socket.Rilda
The client won't throw an IOException. It might throw an EOFException, depending on what read method it called.Rilda
@EJP Since EOFException extends from IOException, it amounts to just about the same thing, depending on what level of the exception you want to handle. The "might" part is awesome to knowStaghound
It only amounts to the same thing if it gets thrown, and none of the three read() methods throw it.Rilda

© 2022 - 2024 — McMap. All rights reserved.