我们有一个客户端和服务器应用程序,目前正在同一台Windows 7 64位计算机上进行测试。它们都是用C#编写的,并使用P / Invoke调用Winsock2库。
该应用程序在没有任何错误的情况下整体运行良好。并且tcp / ip上每个“跳”的延迟平均约为350微秒。
然而,有时在收到数据包之前有超过40到50毫秒的长时间延迟,然后突然间它们都会到达。
到目前为止诊断的努力:
在接收数据的这些延迟期间,服务器继续记录它正在发送数据包。它被设置为每1毫秒发送一次测试数据包,它会在15或20之间发送,有时在客户端收到任何数据之前发送50毫秒。
tcpdump用于在环回适配器上嗅探数据包,并显示在此延迟期间,通常会有从服务器端口(6488)到客户端端口(61743)的流量。
客户端在循环中调用select()winsock2调用,因此在select()调用之前通过计数器进行日志记录表明它具有正确的文件描述符。当然,这在延迟之前和之后都可以正常工作。
在select()调用之后立即进一步记录显示fd不存在 - 这意味着套接字上的读取将被阻止。但是,在没有任何延迟的传输期间,日志记录显示它按预期工作,以便select()返回套接字的fd以执行非阻塞读取。
简而言之,环回适配器似乎在最终将这些数据包传送到接收端之前将这些数据包保存了一段时间。
还有其他想法或解决方案吗?
有些想法是经常声称重叠的I / O在Windows上运行得更好但是如果你需要监听超过64个套接字,这似乎只对可伸缩性有影响。
切换到重叠是否可以解决问题?我们希望避免,因为这会增加项目的截止日期和预算。这应该适用于select()就好了。
此外,Windows中处理环回的进程或线程是否可以进行上下文切换或其他内容,如果有,是否有办法对其进行配置以避免这些延迟?
编辑:正确答案是确保禁用Nagle算法。我们认为它已被禁用,但这就是发现错误的地方 - 在我们内部实现的SetSocketOption()中,我们使用GetSocketOption()进行验证。所以事实证明你必须在连接或绑定套接字之前设置NoDelay,否则它会无声地产生任何影响。
非常感谢Fun Mun Pieng的正确答案!
答案 0 :(得分:3)
我怀疑这可能是Nagle algorithm所致。以下代码禁用它:
socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true);