在Windows CE 6.0上启用Tcp Keepalive

时间:2016-02-09 22:02:57

标签: c# sockets tcp windows-ce

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

到目前为止,我发现了以下选项:

使用System.Net.Socket类上的SetSocketOption设置keepalive:

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

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

然后我尝试使用socket.IoControl,如在线的几个来源所建议的那样设置此套接字选项,包括超时值,但它只会导致SocketException(“提供了无效的参数”)。

实施例

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的已知限制是否无法为每个连接设置keep-alive?

4 个答案:

答案 0 :(得分:1)

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

最后,我手动实现了keep-alive,即通过连接发送内容。这很容易做到,因为你偶尔会有一个低优先级的线程。

答案 1 :(得分:0)

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

for (n = i = ref = 0, ref1 = 100; ref <= ref1 ? i < ref1 : i > ref1; n = ref <= ref1 ? ++i : --i) {

这么长的故事很短 - 当收到Keep-Alive时,你知道连接已经结束,但是当它没有 - 你什么都不知道。非常像John Snow。

在我看来,最佳解决方案已经发布 - 你可以在每一端添加另一个线程,它只监听你自己的Keep-Alive(或任何)数据包,并在出现问题时通知你。

答案 2 :(得分:0)

我目前无法访问CE6.0设备,但显示的代码为

  • 适用于CE7.0 (IOControl调用成功)
  • 在CE5.0上不起作用(抛出SocketException)

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

顺便说一下,ioctl代码不是两次调用BitConverter,而是可以像这样生成:

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

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

答案 3 :(得分:0)

我刚试过在我的Windows CE 7应用程序中使用SIO_KEEPALIVE_VALS代码来处理WSAIoctl()函数。虽然WSAIoctl(SIO_KEEPALIVE_VALS)返回0,这意味着成功,但TCP Keepalive数据包未被发送(在Wireshark中测试)。所以代码似乎无法在Windows CE上运行

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

或者只是使用另一种更可靠的detecting broken connections机制,就像心跳消息一样。