Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detecting unexpected socket disconnect

Tags:

c#

sockets

This is not a question about how to do this, but a question about whether it's wrong what I'm doing. I've read that it's not possible to detect if a socket is closed unexpectedly (like killing the server/client process, pulling the network cable) while waiting for data (BeginReceive), without use of timers or regular sent messages, etc. But for quite a while I've been using the following setup to do this, and so far it has always worked perfectly.

public void OnReceive(IAsyncResult result)
{
    try
    {
        var bytesReceived = this.Socket.EndReceive(result);

        if (bytesReceived <= 0)
        {
            // normal disconnect
            return;
        }

        // ...

        this.Socket.BeginReceive...;
    }
    catch // SocketException
    {
        // abnormal disconnect
    }
}

Now, since I've read it's not easily possible, I'm wondering if there's something wrong with my method. Is there? Or is there a difference between killing processes and pulling cables and similar?

like image 341
Mars Avatar asked Jul 05 '12 08:07

Mars


People also ask

How can we tell if a socket has been disconnected by our peer?

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.

How does TCP detect disconnect?

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.

What does socket disconnected mean?

In BioStar 1's event logs you may see some Event messages saying Server Socket Disconnected or Server Socket Connected. This basically means that the device has lost connection with the server and then it connected to the server again. This may caused by network instability or because of the server PC.


1 Answers

It's perfectly possible and OK to do this. The general idea is:

If EndReceive returns anything other than zero, you have incoming data to process.

If EndReceive returns zero, the remote host has closed its end of the connection. That means it can still receive data you send if it's programmed to do so, but cannot send any more of its own under any circumstances. Usually when this happens you will also close your end the connection thus completing an orderly shutdown, but that's not mandatory.

If EndReceive throws, there has been an abnormal termination of the connection (process killed, network cable cut, power lost, etc).

A couple of points you have to pay attention to:

  1. EndReceive can never return less than zero (the test in your code is misleading).
  2. If it throws it can throw other types of exception in addition to SocketException.
  3. If it returns zero you must be careful to stop calling BeginReceive; otherwise you will begin an infinite and meaningless ping-pong game between BeginReceive and EndReceive (it will show in your CPU usage). Your code already does this, so no need to change anything.
like image 134
Jon Avatar answered Sep 20 '22 06:09

Jon