13

I am looking for a way to do a keep alive check in .NET. The scenario is for both UDP and TCP.

Currently in TCP what I do is that one side connects and when there is no data to send it sends a keep alive every X seconds.

I want the other side to check for data, and if non was received in X seconds, to raise an event or so.

One way i tried to do was do a blocking receive and set the socket's RecieveTimeout to X seconds. But the problem was whenever the Timeout happened, the socket's Receive would throw an SocketExeception and the socket on this side would close, is this the correct behaviour ? why does the socket close/die after the timeout instead of just going on ?

A check if there is data and sleep isn't acceptable (since I might be lagging on receiving data while sleeping).

So what is the best way to go about this, and why is the method i described on the other side failing ?

4 Answers4

20

If you literally mean "KeepAlive", try the following.

    public static void SetTcpKeepAlive(Socket socket, uint keepaliveTime, uint keepaliveInterval)
    {
        /* the native structure
        struct tcp_keepalive {
        ULONG onoff;
        ULONG keepalivetime;
        ULONG keepaliveinterval;
        };
        */

        // marshal the equivalent of the native structure into a byte array
        uint dummy = 0;
        byte[] inOptionValues = new byte[Marshal.SizeOf(dummy) * 3];
        BitConverter.GetBytes((uint)(keepaliveTime)).CopyTo(inOptionValues, 0);
        BitConverter.GetBytes((uint)keepaliveTime).CopyTo(inOptionValues, Marshal.SizeOf(dummy));
        BitConverter.GetBytes((uint)keepaliveInterval).CopyTo(inOptionValues, Marshal.SizeOf(dummy) * 2);

        // write SIO_VALS to Socket IOControl
        socket.IOControl(IOControlCode.KeepAliveValues, inOptionValues, null);
    }

Note the time units are in milliseconds.

Jason C
  • 38,729
  • 14
  • 126
  • 182
Greg Dean
  • 29,221
  • 14
  • 67
  • 78
  • 8
    It's amusing to me that that you would reply to someone that is trying to help you in such a manner. – Greg Dean Oct 10 '08 at 04:37
  • 1
    Worth clarifying that this answer is the only one in C# that allows you to do TCP level keepalives instead of doing it manually in code (it's set-and-forget) and allows you to choose the timeout (turning on SocketOptionName.KeepAlive using SetSocketOption uses a 2 hour timeout, much too long for most applications). More info here: http://blog.stephencleary.com/2009/05/detection-of-half-open-dropped.html – Derek Jan 11 '17 at 00:15
  • I'm assuming this is only required on the Client side. Anything required on the server side? – Sal Apr 23 '18 at 15:40
3

In case you have a tcp server which just writes data at irregular intervals and you'd like to have keep alive running in background:

tcpClient.Client.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveInterval, 1);
tcpClient.Client.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveTime, 2);
tcpClient.Client.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveRetryCount, 2);
tcpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);

Will cause an async read to throw a timeout exception if the server doesn't (automatically usually) replies to tcp keep alives.

Guillermo Ruffino
  • 2,940
  • 1
  • 26
  • 23
1

According to MSDN, a SocketException thrown when ReceiveTimeout is exceeded in Receive call will not close the socket. There is something else going on in your code.

Check the caught SocketException details - maybe it's not a timeout after all. Maybe the other side of the connection shuts down the socket.

Consider enabling network tracing to diagnose the exact source of your problems: look for "Network Tracing" on MSDN (can't provide you with a link, since right now MSDN is down).

qbeuek
  • 4,156
  • 4
  • 19
  • 17
  • Actually the other side still sees the socket as an opened (while this side doesn't). This part of the code isn't complex, i'll try to reproduce it in a smaller test case. –  Oct 04 '08 at 13:27
0

Since you cannot use the blocking (synchronous) receive, you will have to settle for the asynchronous handling. Fortunately that's quite easy to do with .NET. Look for the description of BeginReceive() and EndReceive(). Or check out this article or this.

As for the timeout behaviour I found no conclusive description of this. Since it's not documented otherwise you have to assume that it's the intended behaviour.

TToni
  • 9,145
  • 1
  • 28
  • 42
  • 1
    Yeah, forgot to mention asynchronous operations, but I guess my question is does anybody have experience with RecieveTimeout and why it fails in the above way (cause then my code would be even easier then using RecieveTimeout. –  Oct 04 '08 at 10:35