在 Windows CE 6.0 上启用 Tcp Keepalive

本文关键字:启用 Tcp Keepalive Windows CE | 更新日期: 2023-09-27 18:33:52

我们正在寻找一种方法,使用 .net Compact Framework 3.5 为 Windows CE 6.0 上的客户端套接字启用 TCP keepalive。

到目前为止,我已经找到了这些选项:

在 System.Net.Socket 类上使用 SetSocketOption 设置保持连接:

socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);

这实际上有效,但使用 windows-global 设置进行保持连接,即每隔一小时检查一次连接,这对于我们的用例来说太少了。可以通过更改 [HKEY_LOCAL_MACHINE''Comm''Tcpip''Parms ] 下的注册表项来更改此超时设置(全局(。这将是我的回退解决方案,但我宁愿在每个连接的基础上设置超时。

然后我尝试使用套接字。IoControl 按照在线多个来源的建议设置此套接字选项,包括超时值,但它只会导致套接字异常("提供了无效参数"(。

Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// The native structure for this is defined in mstcpip.h as:
//struct tcp_keepalive {
//u_long onoff;
//u_long keepalivetime;
//u_long keepaliveinterval;
//};
//Set to on, 10 seconds and 1 second. From examples online u_long should be interpreted as unsigned 32bit.
byte[] inValue = new[] { (uint)1, (uint)10000, (uint)1000 }
.SelectMany(x => BitConverter.GetBytes(x))
.ToArray();
//0x98000004 is constant for SIO_KEEPALIVE_VALS found in mstcpip.h
int ioControlCodeKeepAliveValues = BitConverter.ToInt32(BitConverter.GetBytes(0x98000004), 0);
// Throws "An invalid argument was supplied" SocketException 
socket.IOControl(ioControlCodeKeepAliveValues, inValue, null);
socket.Connect(new IPEndPoint(IPAddress.Parse("192.168.0.120"),80));

此代码是否正确,还是 Windows CE 6 的已知限制,无法为每个连接设置保持活动状态?

在 Windows CE 6.0 上启用 Tcp Keepalive

已经有一段时间了,但我也看过这个。最后,我决定摆弄注册表是不便携的,并且在新机器上安装时很容易忘记。我不太记得我尝试了什么东西,但我确实记得它非常乏味,最终没有产生令人满意的解决方案。我认为在很多情况下,文档中的某些 API 调用看起来像是正确的事情,但结果却是浪费时间。我应该注意的是,我在Windows Server上,而不是CE。

最后,我手动实现了保持活动状态,即通过连接发送一些东西。这很容易做到,因为您可以偶尔让低优先级线程执行此操作。

另外,您必须记住,TCP内置的Keep-Alive机制也不是很可靠。通过阅读许多论文(例如来自思科的论文(,我注意到您不能保证网络设备将传输长度为 0 的 TCP 数据包,这基本上是一个 Keep-Alive 数据包。甚至 TCP RFC 也敦促不要使用此解决方案:

Implementors MAY include "keep-alives" in their TCP implementations, although this practice is not universally accepted. If keep-alives are included, the application MUST be able to turn them on or off for each TCP connection, and they MUST default to off.

长话短说 - 当收到Keep-Alive时,你知道连接已启动,但当它没有时 - 您什么都不知道。很像约翰·斯诺。

在我看来,最好的解决方案已经发布 - 您可以在两端添加另一个线程,该线程仅侦听您自己的 Keep-Alive(或任何(数据包,并在出现问题时通知您。

我目前无法访问 CE6.0 设备,但代码如图所示

  • 适用于 CE7.0(IOControl 调用成功(
  • 在 CE5.0 上不起作用(抛出套接字异常(

因此,我的猜测是 CE6.0 根本不支持SIO_KEEPALIVE_VALS

顺便说一句,与其调用BitConverter两次,IOCTL 代码可以像这样生成:

int ioctl;
unchecked { ioctl = (int)0x98000004; }

就我个人而言,我觉得这更具可读性,但话又说回来,并不是每个人都喜欢在他们的代码中使用未经检查的块和强制转换。

我刚刚尝试使用Windows CE 7应用程序中WSAIoctl((函数的SIO_KEEPALIVE_VALS代码。虽然WSAIoctl(SIO_KEEPALIVE_VALS(返回0,这意味着成功,但TCP Keepalive数据包没有被发送(在Wireshark中测试(。因此,该代码似乎不适用于Windows CE。

因此,似乎在注册表中设置系统范围的保持活动参数(时间,周期和计数(,然后在应用程序代码中为套接字启用保持活动是Windows CE上的唯一解决方案。

或者只是使用其他更可靠的机制来检测断开的连接,例如心跳消息。