【问题标题】:Problem With Packet Delays on TCP/IP Windows 7 loopback adapter (or bug in software?)TCP/IP Windows 7 环回适配器上的数据包延迟问题(或软件中的错误?)
【发布时间】:2011-03-16 05:50:51
【问题描述】:

我们目前在同一台 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 中处理环回的进程或线程是否可以进行上下文切换或其他什么,如果是这样,有没有办法对其进行配置以避免这些延迟?

编辑:正确的答案是确保禁用 Nagle 算法。我们认为它已被禁用,但这就是发现错误的地方——在我们内部实现的 SetSocketOption() 中,我们使用 GetSocketOption() 来验证。所以事实证明你必须在连接或绑定套接字之前设置 NoDelay,否则它会默默地失效。

非常感谢Fun Mun Pieng的正确答案!!!

【问题讨论】:

  • JOOI,你为什么要 P/invoking Winsock,而不是使用内置的 .NET 网络类?
  • 这是由于性能测试比较和不喜欢 .Net 用于异步的线程模型,当线程进入休眠状态时会导致非常昂贵的上下文切换。相反,我构建了一个基于“尾递归”的“纤程”或“延续”风格的任务调度程序,该调度程序共享线程并且从不引起任何上下文切换。主线程在实时处理期间从不休眠。它具有近乎实时的计时器和其他实时功能。它的速度很快,并且可以跨多个内核线性扩展。 .Net 团队已经开始制作其中的一些,但还不是全部。

标签: c# windows-7 tcp winsock2 low-latency


【解决方案1】:

我怀疑这可能是由于Nagle algorithm。以下代码将其禁用:

socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true);

【讨论】:

  • 谢谢。不过,我已经有了禁用 Nagle 的代码。也许,我需要仔细检查并验证 NoDelay 是否使用 GetSocketOption 正确设置。顺便说一句,您的代码行与帖子中提到的完全不一样,我编写了自己的 tcp/库,而不是 .Net 中包含的。
  • 好的,在实现 GetSocketOption 之后,结果证明 NoDelay 已关闭,因为现在实验表明您必须在连接套接字或绑定之前设置 NoDelay。所以,事实上,你的答案是正确的!谢谢!!
猜你喜欢
  • 2012-07-01
  • 1970-01-01
  • 2019-03-04
  • 2021-04-17
  • 2011-09-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多