如何强制我的 C# 应用程序立即确认 TCP 数据报?
Posted
技术标签:
【中文标题】如何强制我的 C# 应用程序立即确认 TCP 数据报?【英文标题】:How can I force my C# app to acknowledge TCP datagrams without delay? 【发布时间】:2011-04-28 21:10:45 【问题描述】:我尝试使用 TcpClient.NoDelay = true,但它直到 200 毫秒后才发回确认。我更改了网络适配器的 Windows 注册表设置以禁用 Nagle 算法,这很有效,ACK 会立即发送。难道不应该有办法在不更改注册表设置的情况下禁用 200 毫秒延迟吗?
更新:感谢有关 UDP 的建议。我同意 UDP 是应用程序的正确协议,但不幸的是,我正在处理一个目前只有 TCP 接口的设备,所以我的双手被绑在那里。
【问题讨论】:
【参考方案1】:ACK 数据包是底层操作系统的 TCP/IP 堆栈内部工作的问题。无论如何,您的应用程序不应受到 TCP 协议的标准行为的损害。如果是,你应该考虑使用其他的东西,比如 UDP。
【讨论】:
【参考方案2】:NoDelay 不会像您认为的那样做。它禁用 Nagle 算法,这是一种优化,如果一个完整的数据包还没有排队发送以减少发送的数据包数量,它会等待一小段时间。这与承认无关。
如果您想无延迟地发送数据包,请使用 UDP。 TCP必须等待确认才能知道它是否必须重新发送数据包,这是一种防止缓冲区溢出和丢失数据的安全机制。
编辑:
重新阅读您的问题后,您的问题似乎有点误导。如果在适配器中禁用 nagle 有效,那么这意味着您的问题是数据包没有立即SENT,而不是确认没有立即返回。 ack马上就返回了,只是发送延迟是问题。
您是在打开套接字之后还是之前设置 NoDelay 选项?设置后是否检查 NoDelay 的状态以确保已设置?将其设置为 true 可能会失败,在这种情况下,即使您设置了它,它仍然是 false。
【讨论】:
您对我理解 Nagle 错误的看法可能是对的。我更改了注册表中的 TcpAckFrequency,这使得 ACK 立即发送。【参考方案3】:我知道这是一个老问题,但我刚刚发现它,虽然我完全同意这个说法: “ACK 数据包是底层操作系统 TCP/IP 堆栈内部工作的问题。”
我完全不同意这种说法: “无论如何,您的应用程序不应受到 TCP 协议的标准行为的损害。”
如果那是真的! TCP_NODELAY 关闭,TCP_QUICKACK 也关闭的 TCP 套接字的默认行为不是吗? AFAIK 在我开发的所有平台上都是这种情况,如果我弄错了,请纠正我。
考虑一下客户端将服务请求分解为多个小数据包的情况。服务器在第一个数据包之后等待更多,然后它才会确认,因为快速确认被禁用并且它认为等待将是一种优化。 “肯定还有更多,对吧?我会在多个数据包到达后一次确认它们!”。但是客户端在发送更多信息之前正在等待 ACK,因为 tinygram 预防(也称为 nagle 算法)被禁用,并且下一个数据包远低于最大有效负载。因此,它是否受到损害取决于您的应用程序的性质,但某些应用程序肯定会因产生额外的 RTT 延迟而受到损害。应用层与网络层并没有完全解耦。现在想象有问题的应用程序正在发出 HTTP 请求。当然,你可以说它不应该拆分它的请求,但这样做并不是无效的,底层网络层现在正在对你造成伤害。在这种情况下,切换到 UDP 也不完全是一种选择。另外,有点搞笑的是,一些 UDP 库实现了他们自己的 tinygram 预防版本并默认启用它(例如 RakNet)。
最后,抱歉,我没有足够的代表发表评论,所以这是一个答案:'( 但既然这是一个答案,我的实际反应是检查你是否可以通过 C# 的相当于 WinSock 的 setsockopt 启用快速确认。如果可以的话,一定要在客户端和服务器上这样做,如果没有及时收到 ACK 是一个问题。如果您不想等待任何数量的出站缓冲,那么禁用 tinygram 预防可能是正确的举措,尽管它可能会导致其他副作用。当然,无论多么小,您都必须为每个有效负载添加 TCP/IP 标头开销。最后,始终使用数据包嗅探器查看到底发生了什么,以便您尝试仅修复损坏的部分。
参考资料: John Nagle 对我上面概述的问题的基本回应 https://news.ycombinator.com/item?id=10607422
【讨论】:
以上是关于如何强制我的 C# 应用程序立即确认 TCP 数据报?的主要内容,如果未能解决你的问题,请参考以下文章