65.9K
CodeProject 正在变化。 阅读更多。
Home

设置 Keep-Alive 值

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.33/5 (3投票s)

2010 年 10 月 12 日

CPOL

2分钟阅读

viewsIcon

95080

SetKeepAliveValues 方法启用或禁用每个连接的 TCP keep-alive 选项设置,该选项指定 TCP keep-alive 超时和间隔。

评论改编自以下站点

引言

为了理解 TCP keepalive(我们简称 keepalive)的作用,您只需要阅读名称:保持 TCP 活跃。 这意味着您将能够检查您连接的套接字(也称为 TCP 套接字),并确定连接是否仍然启动并运行,或者是否已断开。

背景

在大多数情况下,了解 TCP keepalive 没有必要,但在特定情况下,它可能非常有用。您需要了解基本的 TCP/IP 网络概念。

什么是 TCP keepalive?

keepalive 的概念非常简单:当您设置 TCP 连接时,您会关联一组计时器。 其中一些计时器处理 keepalive 过程。 当 keepalive 计时器达到零时,您会向您的对等方发送一个没有数据的 keepalive 探测数据包,并且 ACK 标志已打开。 由于 TCP/IP 规范,您可以这样做,作为一种重复的 ACK,并且远程端点不会有任何参数,因为 TCP 是面向流的协议。 另一方面,您将收到来自远程主机的回复(远程主机根本不需要支持 keepalive,只需支持 TCP/IP),没有数据且设置了 ACK。

如果您收到对 keepalive 探测的回复,您可以断言连接仍然启动并运行,而无需担心用户级实现。 事实上,TCP 允许您处理流,而不是数据包,因此零长度的数据包对于用户程序来说并不危险。

此过程非常有用,因为如果其他对等方失去连接(例如通过重新启动),即使您没有流量,您也会注意到连接已断开。 如果您的对等方未回复 keepalive 探测,您可以断言该连接不能被认为是有效的,然后采取正确的操作。

Using the Code

SetKeepAliveValues 方法启用或禁用 TCP keep-alive 选项的每个连接设置,该选项指定用于 TCP keep-alive 数据包的 TCP keep-alive 超时和间隔。 有关 keep-alive 选项的更多信息,请参见 RFC 1122 中指定的互联网主机通信层要求的 4.2.3.6 节,该节可在 IETF 网站上找到。

传递给 Socket.IOControloptionInValue 参数应指向 Mstcpip.h 头文件中定义的 tcp_keepalive 结构。 该结构定义如下

/* Argument structure for SIO_KEEPALIVE_VALS */
struct tcp_keepalive {
	    u_long  onoff;
	    u_long  keepalivetime;
	    u_long  keepaliveinterval;
		};

tcp_keepalive C struct 转换为 C# struct

// Convert tcp_keepalive C struct To C# struct
[
   	System.Runtime.InteropServices.StructLayout
   	(
   		System.Runtime.InteropServices.LayoutKind.Explicit
   	)
]
unsafe struct TcpKeepAlive
{
    [System.Runtime.InteropServices.FieldOffset(0)]
    [
      	System.Runtime.InteropServices.MarshalAs
       	(
       		System.Runtime.InteropServices.UnmanagedType.ByValArray,
       		SizeConst = 12
       	)
    ]
    public fixed byte Bytes[12];

    [System.Runtime.InteropServices.FieldOffset(0)]
    public uint On_Off;
        
    [System.Runtime.InteropServices.FieldOffset(4)]
    public uint KeepaLiveTime;
        
    [System.Runtime.InteropServices.FieldOffset(8)]
    public uint KeepaLiveInterval;
}

public int SetKeepAliveValues
  	(
   		System.Net.Sockets.Socket Socket,
   		bool On_Off,
   		uint KeepaLiveTime,
   		uint KeepaLiveInterval
   	)
{       
    int Result = -1;

    unsafe
    {
        TcpKeepAlive KeepAliveValues = new TcpKeepAlive();

        KeepAliveValues.On_Off = Convert.ToUInt32(On_Off);
        KeepAliveValues.KeepaLiveTime = KeepaLiveTime;
        KeepAliveValues.KeepaLiveInterval = KeepaLiveInterval;

        byte[] InValue = new byte[12];

        for (int I = 0; I < 12; I++)
            InValue[I] = KeepAliveValues.Bytes[I];

        Result = Socket.IOControl(IOControlCode.KeepAliveValues, InValue, null);
    }

    return Result;
}

调用方法

System.Net.Sockets.Socket Socket = new System.Net.Sockets.Socket
	(
		System.Net.Sockets.AddressFamily.InterNetwork,
		System.Net.Sockets.SocketType.Stream,
		System.Net.Sockets.ProtocolType.Tcp
	);
	
// Set 10 Hours: 10 * 60 * 60 * 1000 = 36,000,000 every 1 Second 1000
SetKeepAliveValues(Socket, true, 36000000, 1000);

历史

  • 2010 年 10 月 12 日:首次发布
© . All rights reserved.