什么时候应该使用 TCP_NODELAY,什么时候应该使用 TCP_CORK?

Posted

技术标签:

【中文标题】什么时候应该使用 TCP_NODELAY,什么时候应该使用 TCP_CORK?【英文标题】:When should I use TCP_NODELAY and when TCP_CORK? 【发布时间】:2011-04-15 05:55:15 【问题描述】:

我知道他们都禁用了 Nagle 的算法。

什么时候应该/不应该使用它们中的每一个?

【问题讨论】:

【参考方案1】:

这是一种优化,就像任何优化一样:

    不要使用它 等到性能出现问题,然后确定套接字延迟肯定是它的原因,并且测试证明这肯定会解决它,而且这是修复它的最简单方法,那就去做吧。

基本上,目的是避免发送多个可以使用单个帧的帧,使用 sendfile() 及其朋友。

因此,例如,在 Web 服务器中,您发送标头后跟文件内容,标头将在内存中组装,然后文件将直接由内核发送。 TCP_CORK 允许您在单个帧中发送文件头和文件的开头,即使使用 TCP_NODELAY,否则会导致第一个块立即发送出去。

【讨论】:

Nagle 本身就是一种优化,因此根据您的逻辑,您应该将其关闭并仅在需要时将其打开 :-) Nagle 默认是启用的,你不需要写任何代码来启用它,所以无论如何它都会发生。不,如果你正在编写自己的 TCP 堆栈,如果你不需要实现 Nagle,你就不会这样做。 如果这在几年后真的发生了(不再实施它),我不会感到惊讶。大约 30 或 40 年前的主要问题是人们在 telnet 上以大约每秒 2 个字符的速度打字会为每个字符生成一个数据包。现在这几乎不是问题,因为带宽要高得多,远程登录在流量方面没有发挥重要作用,并且无论如何都将块密码应用于几乎所有远程登录流量。您无法使用 128 位分组密码发送少于 16 个字节的数据(无论如何,如果您想在另一端对其进行解码,则无法发送)。 @camh 我知道你在开玩笑,但为了保护 OP,禁用 Nagle 的行为有时是对 latency 变量的优化。 @camh 老实说,我最初阅读 Mark 的建议是“在确定需要延迟之前使用 NODELAY”,因为 Nagle 是我心目中的“优化”。在这种情况下,这绝对是一个模糊的建议。【参考方案2】:

TCP_CORK 与 TCP_NODELAY 相反。前者强制数据包累积延迟;后者禁用它。

【讨论】:

TCP_CORK 不是 TCP_NODELAY 的反义词。 Nagle 的算法在等待返回 ACK 时聚合数据,后一个选项禁用该返回;前者根据缓冲压力聚合数据。【参考方案3】:

首先,并非两者都禁用了 Nagle 算法。

Nagle 的算法用于减少线路中更多的小型网络数据包。该算法是:如果数据小于限制(通常是 MSS),则等待直到收到先前发送的数据包的 ACK,同时累积来自用户的数据。然后发送累积的数据。

if [ data > MSS ]
    send(data)
else
    wait until ACK for previously sent data and accumulate data in send buffer (data)
    And after receiving the ACK send(data)

这将有助于 telnet 等应用程序。但是,在发送流数据时等待 ACK 可能会增加延迟。此外,如果接收方实施“延迟 ACK 策略”,则会导致暂时的死锁情况。在这种情况下,禁用 Nagle 算法是更好的选择。

所以 TCP_NODELAY 用于禁用 Nagle 算法。

TCP_CORK 积极地积累数据。如果在套接字中启用了 TCP_CORK,它将不会发送数据,直到缓冲区填充到固定限制。与 Nagle 的算法类似,它也从用户那里累积数据,但直到缓冲区填充到固定限制,直到收到 ACK。这在发送多个数据块时很有用。但是在使用 TCP_CORK 时必须更加小心。

直到 2.6 内核,这两个选项都是互斥的。但是在后来的内核中,它们可以同时存在。在这种情况下,TCP_CORK 将被优先考虑。

参考:

http://baus.net/on-tcp_cork/ http://ccr.sigcomm.org/archive/2001/jan01/ccr-200101-mogul.pdf

【讨论】:

请记住 Hussein Galal 的回答,它阐明 TCP_CORK 在发送数据之前最多只能延迟 200 毫秒。 “这将有助于 telnet 等应用程序。”?反之亦然。如果您按下一个键,这将延迟将您的按键发送到另一侧,直到收到最后一次按键的 ACK。这会在按键和发送按键之间引入很高的延迟,我不知道任何情况下这是可取的。【参考方案4】:

TCP_NODELAY

用于禁用 Nagle 算法以改进 TCP/IP 网络并通过等待收到对先前发送数据的确认以发送累积的数据包来减少数据包的数量。

//来自tcp(7)手册:

TCP_CORK(或在 FreeBSD 中为 TCP_NOPUSH

如果设置,则不发送部分帧。再次清除该选项时,将发送所有排队的部分帧。这对于在调用 sendfile(2) 之前添加标头或吞吐量优化很有用。正如目前实施的那样,有一个 ** 200 毫秒的上限** 输出被 TCP_CORK 塞住的时间。 如果达到此上限,则会自动传输排队的数据。仅从 Linux 2.5.71 起,此选项才能与 TCP_NODELAY 结合使用。此选项不应在旨在可移植的代码中使用。

【讨论】:

感谢您指出许多指南完全错误的地方,即 TCP_CORK 仅延迟 200 毫秒(最大值),它并不是真正的 CORK,直到被移除。

以上是关于什么时候应该使用 TCP_NODELAY,什么时候应该使用 TCP_CORK?的主要内容,如果未能解决你的问题,请参考以下文章

什么时候应该使用 Sql Azure,什么时候应该使用表存储?

什么时候应该使用 Microsoft.Owin 实现,什么时候应该使用 AspNetCore?

什么时候应该使用 JSF 组件,什么时候应该使用 html 标签? [关闭]

什么时候应该使用 var,什么时候应该使用 string、ulong、int 等 [重复]

什么时候应该使用标准的 html 标签/输入,什么时候应该使用 asp.net 控件?

什么时候应该使用 jQuery deferred 的“then”方法,什么时候应该使用“pipe”方法?