Java socket API: How to tell if a connection has been closed?
I am running into some issues with the Java socket API. I am trying to display the number of players currently connected to my game. It is easy to determine when a player has connected. However, it seems unnecessarily difficult to determine when a player has disconnected using the socket API.
Calling isConnected()
on a socket that has been disconnected remotely always seems to return true
. Similarly, calling isClosed()
on a socket that has been closed remotely always seems to return false
. I have read that to actually determine whether or not a socket has been closed, data must be written to the output stream and an exception must be caught. This seems like a really unclean way to handle this situation. We would just constantly have to spam a garbage message over the network to ever know when a socket had closed.
Is there any other solution?
Solution 1:
There is no TCP API that will tell you the current state of the connection. isConnected()
and isClosed()
tell you the current state of your socket. Not the same thing.
isConnected()
tells you whether you have connected this socket. You have, so it returns true.isClosed()
tells you whether you have closed this socket. Until you have, it returns false.-
If the peer has closed the connection in an orderly way
-
read()
returns -1 -
readLine()
returnsnull
readXXX()
throwsEOFException
for any other XXX.A write will throw an
IOException
: 'connection reset by peer', eventually, subject to buffering delays.
-
If the connection has dropped for any other reason, a write will throw an
IOException
, eventually, as above, and a read may do the same thing.If the peer is still connected but not using the connection, a read timeout can be used.
Contrary to what you may read elsewhere,
ClosedChannelException
doesn't tell you this. [Neither doesSocketException: socket closed.
] It only tells you that you closed the channel, and then continued to use it. In other words, a programming error on your part. It does not indicate a closed connection.-
As a result of some experiments with Java 7 on Windows XP it also appears that if:
- you're selecting on
OP_READ
-
select()
returns a value of greater than zero - the associated
SelectionKey
is already invalid (key.isValid() == false
)
it means the peer has reset the connection. However this may be peculiar to either the JRE version or platform.
- you're selecting on
Solution 2:
It is general practice in various messaging protocols to keep heartbeating each other (keep sending ping packets) the packet does not need to be very large. The probing mechanism will allow you to detect the disconnected client even before TCP figures it out in general (TCP timeout is far higher) Send a probe and wait for say 5 seconds for a reply, if you do not see reply for say 2-3 subsequent probes, your player is disconnected.
Also, related question