Socket Keep-Alive扩展如何工作?C#

3
在编写Socket客户端/服务器时,我考虑实现HeartBeat来了解客户端是否存活,但后来寻找其他方法并发现这段代码似乎从描述中确实可以做到这一点:
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);
    }
}

似乎比实现HeartBeat更简单地完成了任务,虽然我不太明白它是如何工作的,看起来似乎在处理非托管代码?如果是这样,为什么要这样做呢?

能否给出解释,谢谢!

1个回答

3
保持连接是TCP协议的一部分。启用KeepAlive后,操作系统将定期向对方发送空包并等待ACK。如果在所需的超时期内未收到ACK,则假定连接已断开,应用程序可以被通知。
然而,除非您有一个只接收数据的套接字或者您的连接长时间处于空闲状态,否则通常不需要使用KeepAlive。
在只接收数据的套接字中,您不发送任何数据,因此检测断开连接的唯一方法是发送空包并等待ACK。
如果另一端发送数据时,您每次发送数据给对方也会检查连接是否断开,因此不需要KeepAlive。请注意,如果您仅在回复另一端发送数据时才发送数据,则仍需要KeepAlive,因为您可能永远无法进入协议的“发送”部分。
同时,如Remy Lebeau在他的评论中指出,长时间处于空闲状态的连接可能需要KeepAlive,因为某些路由器/防火墙在一段时间后关闭空闲连接。

3
However KeepAlive is only require if you have a receive-only socket”这句话不是真的。还有其他使用Keepalive的原因,比如在连接空闲一段时间时保持连接活动状态(比如FTP命令连接在数据连接上进行长时间传输期间处于空闲状态)。一些路由器/防火墙会在一段时间后关闭空闲连接,因此可以使用Keepalive来解决这个问题。 - Remy Lebeau
@RemyLebeau:你说得对,感谢提出。我已经编辑了我的答案以完善它。 - P. Kouvarakis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接