How should I check a (TCP) socket to find out whether it is connected?
I have read about the Socket.Connected
property in MSDN, but it says it only shows the state according to the last I/O. This isn't useful for me, since I want to do this before trying to read from the socket. The remarks section also notes that:
If you need to determine the current state of the connection, make a nonblocking, zero-byte Send call. If the call returns successfully or throws a WAEWOULDBLOCK error code (10035), then the socket is still connected; otherwise, the socket is no longer connected.
The example on the same page shows how to do it.(1) But a post by Ian Griffiths says that I should read from the socket, not send through it.
Another post by Pete Duniho says:
... after you've called
Shutdown()
, callReceive()
until it returns0
(assuming the remote endpoint isn't actually going to send you anything, that will happen as soon as the remote endpoint has received all of your data). Unless you do that, you have no assurance that the remote endpoint has actually received all of the data you sent, even using a lingering socket.
I don't really understand his statement about calling Receive()
to make sure that the remote endpoint has actually received all the data I sent. (Do sockets block receiving until the sending buffer is empty?)
I am confused by the different methods proposed. Could you please explain them?
(1) I wonder why the example for the Socket.Connected
property allocates a 1-byte array, even though it calls Send
with 0 length?
Just use the KeepAlive like @toster-cx says and then use the Socket Connected status to check if the Socket is still connected. Set your receive timeout at the same timeout of the keepalive.
In TCP there is only one way to detect an orderly disconnect, and that is by getting zero as a return value from read()/recv()/recvXXX() when reading. There is also only one reliable way to detect a broken connection: by writing to it.
You could check if the socket is still connected by trying to write to the file descriptor for each socket. Then if the return value of the write is -1 or if errno = EPIPE, you know that socket has been closed.
If you need to determine the current state of the connection, make a nonblocking, zero-byte Send call. If the call returns successfully or throws a WAEWOULDBLOCK error code (10035), then the socket is still connected; otherwise, the socket is no longer connected.
Death of a socket changes its behavior in several ways, so these methods are both valid :)
With both methods you actually check those parts of the socket's behavior that change after disconnection.
I don't really understand his statement about calling Receive() to make sure that the remote endpoint has actually received all the data I sent. (Do sockets block receiving until the sending buffer is empty?)
TCP
is reliable protocol, that means that every packet you send must be acknowledged. Acknowledgement implies sending the packets with ACK
bit set. These packets may or may not contain additional (payload) data.
When the socket is connected, Receive()
will block until the socket receives a packet with non-empty payload. But when the socket is disconnected, Receive()
will return as soon as the last ACK
packet arrives.
Calling Receive()
ensures that you either receive that last ACK
packet from your remote endpoint or a disconnect timeout occurs and you will be able to receive nothing more on this socket.
The example on the same page shows how to do it. (I wonder why does it allocate a 1-byte array, even though it calls Send with 0 length?) But a post by Ian Griffiths says that I should read from the socket, not send through it.
When send()
ing to a socket, you actually try to append some data to the end of the socket queue. Is there is some place left in the buffer, then your Send()
returns instantly, if not, the Send()
blocks until there is some place.
When the socket is in disconnected state, TCP/IP
stack prevents all further operations with the buffer, that's why Send()
returns an error.
Send()
implements a basic pointer check, this means it fails when a NULL
pointer is passed to it. You may probably pass any non-null constant as a pointer, but you better allocate 1 byte instead of making the constant up — just in case.
You may use any method you like, as none of them is resource consuming. As long as they are used for socket connection checking, they are identical.
As for me, I would prefer Receive()
, as this is what you normally run in a cycle and wait for. You get a non-zero from Receive()
, you process data; you get a zero, you process disconnection.
"If you need to determine the current state of the connection, make a nonblocking, zero-byte Send call. If the call returns successfully or throws a WAEWOULDBLOCK error code (10035), then the socket is still connected; otherwise, the socket is no longer connected." -- unfortunately, it doesn't even work!
mySocket.Blocking = false; byte[] buffer = new byte[1]; int iSent = mySocket.Send(buffer, 0, SocketFlags.None); bConnected = mySocket.Connected;
bConnected always ends up as true, and the call always returns successfully, even though the Ethernet cable has been unplugged.
Moreover, and unfortunately == sending any actual data doesn't detect the broken connection, either.
buffer[0] = 0xff ; int iSent = mySocket.Send(buffer, 1, SocketFlags.None);
repeatedly returns 1, as if if had actually sent something. While the device in question isn't even connected any more.
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