我们正在寻找一种方法,使用.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?
答案 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设备,但显示的代码为
因此,我的猜测是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机制,就像心跳消息一样。