3

我们有一个客户端和服务器应用程序当前在同一台 Windows 7 64 位机器上进行测试。它们都是用 C# 编写的,并使用 P/Invoke 调用 Winsock2 库。

该应用程序总体上运行良好,没有任何错误。tcp/ip 上每个“跳跃”的延迟平均约为 350 微秒。

但是,有时在接收数据包之前会有超过 40 到 50 毫秒的非常长的延迟,然后突然它们都会到达。

迄今为止的诊断工作:

  1. 在接收数据的这些延迟期间,服务器继续记录它正在发送数据包。它设置为每 1 毫秒发送一次测试数据包,它会在 15 或 20 毫秒内发送一次测试数据包,有时会在客户端收到任何测试数据包之前长达 50 毫秒。

  2. tcpdump 用于嗅探环回适配器上的数据包,并显示在此延迟期间,像往常一样有从服务器端口 (6488) 到客户端端口 (61743) 的流量。

  3. 客户端在循环中调用 select() winsock2 调用,因此在 select() 调用之前通过计数器记录表明它具有正确的文件描述符。当然,这在延迟前后都可以正常工作。

  4. 在 select() 调用之后立即进一步记录显示 fd 不存在——这意味着对套接字的读取将阻塞。但是,在没有任何延迟的传输期间,日志显示它按预期工作,因此 select() 返回套接字的 fd 以进行非阻塞读取。

简而言之,环回适配器似乎将这些数据包保存在某个地方很长一段时间,然后才最终将它们传送到接收端。

任何进一步的想法或解决方案?

一些想法是它经常声称重叠 I/O 在 Windows 上工作得更好,但如果你需要监听超过 64 个套接字,这似乎只对可伸缩性很重要。

是不是切换到重叠可以解决问题?我们希望避免,因为这会增加项目期限和预算。这应该适用于 select() 就好了。

此外,Windows中处理环回的进程或线程是否可以进行上下文切换或其他什么,如果是这样,是否有办法对其进行配置以避免这些延迟?

Edit: The correct answer was to ensure that the Nagle algorithm was disabled. We thought it was disabled but that's where the bug was found--in our in-house implementation of SetSocketOption() we used GetSocketOption() to verify. So it turns out you must set NoDelay prior to connecting or binding a socket or else it silently fails to have any effect.

Many thanks to Fun Mun Pieng for the correct answer!!!

4

1 回答 1

3

I suspect this may be due to the Nagle algorithm. The following code disables it:

socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true);
于 2011-03-16T06:00:38.620 回答