tags:

views:

5123

answers:

9

How can I detect that a client has disconnected from my server?

I have the following code in my AcceptCallBack method

static Socket handler = null;
public static void AcceptCallback(IAsyncResult ar)
{
  //Accept incoming connection
  Socket listener = (Socket)ar.AsyncState;
  handler = listener.EndAccept(ar);
}

I need to find a way to discover as soon as possible that the client has disconnected from the handler Socket.

I've tried:

  1. handler.Available;
  2. handler.Send(new byte[1], 0, SocketFlags.None);
  3. handler.Receive(new byte[1], 0, SocketFlags.None);

The above approaches work when you are connecting to a server and want to detect when the server disconnects but they do not work when you are the server and want to detect client disconnection.

Any help will be appreciated.

+4  A: 

This is simply not possible. There is no physical connection between you and the server (except in the extremely rare case where you are connecting between two compuers with a loopback cable).

When the connection is closed gracefully, the other side is notified. But if the connection is disconnected some other way (say the users connection is dropped) then the server won't know until it times out (or tries to write to the connection and the ack times out). That's just the way TCP works and you have to live with it.

Therefore, "instantly" is unrealistic. The best you can do is within the timeout period, which depends on the platform the code is running on.

EDIT: If you are only looking for graceful connections, then why not just send a "DISCONNECT" command to the server from your client?

Mystere Man
Thanks but I actually mean a graceful software disconnection, not a physical disconnection. I'm running Windows
All the more reason to worry about physical disconnections when windows crashes :-)
Orion Edwards
+7  A: 

Since there are no events available to signal when the socket is disconnected, you will have to poll it at a frequency that is acceptable to you.

Using this extension method, you can have a reliable method to detect if a socket is disconnected.

static class SocketExtensions
{
  public static bool IsConnected(this Socket socket)
  {
    try
    {
      return !(socket.Poll(1, SelectMode.SelectRead) && socket.Available == 0);
    }
    catch (SocketException) { return false; }
  }
}
Samuel
This worked. Thanks. I changed the method to return !(socket.Available == 0 because I suspect socket.Available is faster than Socket.Poll()
The first parameter of Poll is the timeout in microseconds, I highly doubt you will notice 1 microsecond. ;)
Samuel
This method does not work unless the other end of the connection actually closes/shutdowns the socket. An unplugged network/power cable won't be noticed before the timeout period. The only way to be notified of disconnects right away is with a heartbeat function to continously check the connection.
Qua
@Smart Alec: actually, you should use the example as it's shown above. There is a potential race condition if you change the order: if `socket.Available` returns 0 and you receive a packet just before `socket.Poll` gets called, `Poll` will return true and method will return `false`, although the socket is actually still healthy.
Groo
A: 

You can also check the .IsConnected property of the socket if you were to poll.

theG
This won't work for any of the scenarios (server / client) i presented above
A: 

Implementing heartbeat into your system might be a solution. This is only possible if both client and server are under your control. You can have a DateTime object keeping track of the time when the last bytes were received from the socket. And assume that the socket not responded over a certain interval are lost. This will only work if you have heartbeat/custom keep alive implemented.

Niran
A: 

Can't you just use Select?

Use select on a connected socket. If the select returns with your socket as Ready but the subsequent Receive returns 0 bytes that means the client disconnected the connection. AFAIK, that is the fastest way to determine if the client disconnected.

I do not know C# so just ignore if my solution does not fit in C# (C# does provide select though) or if I had misunderstood the context.

Aditya Sehgal
+1  A: 

"That's just the way TCP works and you have to live with it."

Yup, you're right. It's a fact of life I've come to realize. You will see the same behavior exhibited even in professional applications utilizing this protocol (and even others). I've even seen it occur in online games; you're buddy says "goodbye", and he appears to be online for another 1-2 minutes until the server "cleans house".

You can use the suggested methods here, or implement a "heartbeat", as also suggested. I choose the former. But if I did choose the latter, I'd simply have the server "ping" each client every so often with a single byte, and see if we have a timeout or no response. You could even use a background thread to achieve this with precise timing. Maybe even a combination could be implemented in some sort of options list (enum flags or something) if you're really worried about it. But it's no so big a deal to have a little delay in updating the server, as long as you DO update. It's the internet, and no one expects it to be magic! :)

ATC
+1  A: 

I've found quite useful, another workaround for that!

If you use asynchronous methods for reading data from the network socket (I mean, use BeginReceipt - EndReceipt methods), whenever a connection is terminated; one of these situations appear: Either a message is sent with no data (you can see it with Socket.Available - even though BeginReceipt is triggered, its value will be zero) or Socket.Connection value becomes false in this call (don't try to use EndReceipt then).

I'm posting the function I used, I think you can see what I meant from it better:

//------------------------------------------

private void OnRecieve(IAsyncResult parameter) { Socket sock = (Socket)parameter.AsyncState;

        if((sock.Connected == false)  || (sock.Available == 0))
        {

            // Connection is terminated, either by force or
            // willingly
            return;
        }
        sock.EndReceive(parameter);

        sock.BeginReceive(..., ... , ... , ..., new AsyncCallback(OnRecieve), sock); > // To handle further commands sent by client. "..." zones might change in your code.

}

+1  A: 

More on the heartbeat solution: Detection of Half-Open (Dropped) Connections

Stephen Cleary
A: 

sdaDSAdsaSsSAdsaSA

Luis Zhan
this is jues test
Luis Zhan