I was looking how to detect a ‘client disconnect’ when using a TcpListener.
All the answers seem to be similar to this one:
TcpListener: How can I detect a client disconnect?
Basically, read from the stream and if Read() returns 0 the client had disconnected.
But that’s assuming that a client disconnects after every single stream of data it sent.
We operate in environments where the TCP connect/disconnect overhead is both slow and expensive.
We establish a connection and then we send a number of requests.
Pseudocode:
client.Connect();
client.GetStatus();
client.DoSomething();
client.DoSomethingElse();
client.AndSoOn();
client.Disconnect();
Each call between Connect and Disconnect() sends a stream of data to the server.
The server knows how to analyze and process the streams.
If let the TcpListener read in a loop without ever disconnecting it reads and handles all the messages, but after the client disconnects, the server has no way of knowing that and
it will never release the client and accept new ones.
var read = client.GetStream().Read(buffer, 0, buffer.Length);
if (read > 0)
{
//Process
}
If I let the TcpListener drop the client when read == 0 it only accepts
the first stream of data only to drop the client immediately after.
Of course this means new clients can connect.
There is no artificial delay between the calls,
but in terms of computer time the time between two calls is ‘huge’ of course,
so there will always be a time when read == 0 even though that does not mean
the client has or should be disconnected.
var read = client.GetStream().Read(buffer, 0, buffer.Length);
if (read > 0)
{
//Process
}
else
{
break; //Always executed as soon as the first stream of data has been received
}
So I’m wondering… is there a better way to detect if the client has disconnected?
You could get the underlying socket using the
NetworkStream.Socketproperty and use it’s Receive method for reading.Unlike
NetworkStream.Read, the linked overload ofSocket.Receivewill block until the specified number of bytes have been read, and will only return zero if the remote host shuts down the TCP connection.UPDATE: @jrh’s comment is correct that
NetworkStream.Socketis a protected property and cannot be accessed in this context. In order to get the clientSocket, you could use the TcpListener.AcceptSocket method which returns theSocketobject corresponding to the newly established connection.