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?
The most obvious way to accomplish this is having that process call read on the socket for a connection and check whether read returns 0 (i.e. reads zero bytes from the socket), in which case we know that the connection has been closed.
There is an easy way to check socket connection state via poll call. First, you need to poll socket, whether it has POLLIN event. If socket is not closed and there is data to read then read will return more than zero. If socket is closed then POLLIN flag will be set to one and read will return 0.
close() call shuts down the socket associated with the socket descriptor socket, and frees resources allocated to the socket. If socket refers to an open TCP connection, the connection is closed. If a stream socket is closed when there is input data queued, the TCP connection is reset rather than being cleanly closed.
A "socket closed" error means that the connection has been terminated, however, no specific reason was provided/returned. The "socket closed" error indicates that the connection was lost outside of the control or awareness of the Driver. There can be a number of reasons for that, for example: network failure.
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 -1readLine()
returns null
readXXX()
throws EOFException
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 does SocketException: 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:
OP_READ
select()
returns a value of greater than zeroSelectionKey
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With