J. Doe
J. Doe

Reputation: 915

How does Socket Keep-Alive extension work? C#

While coding Socket client/server, I've thought to implement HeartBeat to know whether client is alive, but then searched for other ways to do so and spotted this piece of code which seems to do exactly that from description:

public static class SocketExtensions
{
    /// <summary>
    ///     A structure used by SetKeepAliveEx Method
    /// </summary>
    [StructLayout(LayoutKind.Sequential)]
    internal struct TcpKeepAlive
    {
        internal uint onoff;
        internal uint keepalivetime;
        internal uint keepaliveinterval;
    };

    /// <summary>
    ///     Sets the Keep-Alive values for the current tcp connection
    /// </summary>
    /// <param name="socket">Current socket instance</param>
    /// <param name="keepAliveInterval">Specifies how often TCP repeats keep-alive transmissions when no response is received. TCP sends keep-alive transmissions to verify that idle connections are still active. This prevents TCP from inadvertently disconnecting active lines.</param>
    /// <param name="keepAliveTime">Specifies how often TCP sends keep-alive transmissions. TCP sends keep-alive transmissions to verify that an idle connection is still active. This entry is used when the remote system is responding to TCP. Otherwise, the interval between transmissions is determined by the value of the keepAliveInterval entry.</param>
    public static void SetKeepAliveEx(this Socket socket, uint keepAliveInterval, uint keepAliveTime)
    {
        var keepAlive = new TcpKeepAlive
        {
            onoff = 1,
            keepaliveinterval = keepAliveInterval,
            keepalivetime = keepAliveTime
        };
        int size = Marshal.SizeOf(keepAlive);
        IntPtr keepAlivePtr = Marshal.AllocHGlobal(size);
        Marshal.StructureToPtr(keepAlive, keepAlivePtr, true);
        var buffer = new byte[size];
        Marshal.Copy(keepAlivePtr, buffer, 0, size);
        Marshal.FreeHGlobal(keepAlivePtr);
        socket.IOControl(IOControlCode.KeepAliveValues, buffer, null);
    }
}

It seems to do the job in a much more simple way than implementing a HeartBeat, although I don't quite understand how it works, seems to be doing something with unmanaged code? And if so, why?

An explanation would be appreciated, thanks!

Upvotes: 3

Views: 3957

Answers (1)

P. Kouvarakis
P. Kouvarakis

Reputation: 1943

KeepAlive is part of the TCP protocol. By enabling KeepAlive, the OS will periodically send empty packets to the other party and wait for an ACK. If no ACK is received within the required timeout period the connection is assumed to be broken and the application can be notified.

However KeepAlive is usually not required unless you have a receive-only socket or your connection is going to be idle for long periods of time.

In a receive-only socket you don't send any data so the only way to detect a broken connection is send a null packet and wait for the ACK.

If OTOH you have a bidirectional socket, every time you send data to the other party you are essentially also checking if the connection was dropped, so no need for KeepAlive's. Note that if you send data only in response to the other end sending data, then you still need KeepAlive because you may never get to the "sending" part of your protocol.

Also, as noted by Remy Lebeau in his comment, a connection that can be idle for long periods, may require KeepAlive as some routers/firewalls close idle connections after awhile.

Upvotes: 3

Related Questions