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

90
我理解两者都禁用了 Nagle 算法。
在什么情况下应该/不应该使用它们?
4个回答

112

首先,它们两个都不能禁用 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将被赋予更高的优先级。

参考:


10
请记住 Hussein Galal 的回答,它澄清了 TCP_CORK 只会在发送数据前最多延迟 200 毫秒。 - b4hand
2
“这将有助于像 Telnet 这样的应用程序。”这并非完全正确。如果您按下一个键,它会延迟发送您的按键到另一端,直到上一个按键的 ACK 被接收。这会在按键和发送之间引入高延迟,我不知道任何情况下这是可取的。 - Mecki

34

TCP_NODELAY

用于禁用 Nagle 算法以优化 TCP/IP 网络并减少数据包数量,等到之前发送的数据得到确认后再发送累积的数据包。

//来源于 tcp(7) 手册:

TCP_CORK(在 FreeBSD 中为 TCP_NOPUSH

若启用,则不会发送部分帧。所有已排队的部分帧都将在该选项被取消时一次性发送。这对于在调用 sendfile(2) 前添加头文件或进行吞吐量优化非常有用。按目前实现,TCP_CORK 可以最长使输出被缓存 200 毫秒。如果达到此上限,则排队的数据将自动传输。从 Linux 2.5.71 开始,此选项只能与 TCP_NODELAY 结合使用。不应在旨在可移植的代码中使用此选项。


7
感谢您指出许多指南都完全错误的一点,那就是TCP_CORK只会延迟200毫秒(最长时间),它不是一个实际的软塞子,需要将其移除才能解除阻塞。 - Orwellophile

9

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

  1. 不要使用它。
  2. 等到性能成为问题时,然后确定套接字延迟确实是问题的原因,并且测试证明这肯定会解决问题,并且这是最简单的解决方法,那么就可以使用它。

基本上,目的是避免发送多个帧,而可以使用单个帧通过sendfile()及其相关函数来发送。

例如,在Web服务器中,您可以先将标题和文件内容组装在内存中,然后文件可以直接由内核发送。TCP_CORK允许您将标题和文件的开头作为单个帧发送,即使使用了TCP_NODELAY,否则第一个块也会立即发送。


60
Nagle本身是一种优化技术,按照您的逻辑,您应该关闭它,只有在需要时才启用它 :-) - camh
3
Nagle 默认是开启的,你不需要编写任何代码来启用它,因此它将自动发生。如果你在编写自己的 TCP 栈,如果不需要实现 Nagle,则不会这样做。 - MarkR
8
如果在未来几年内有人不再实施它,我并不会感到惊讶。大约三四十年前的主要问题是,以每秒大约2个字符的速度在telnet上输入文本将为每个字符生成一个数据包。随着带宽显著提高、远程登录在流量方面不再占据重要地位,并且块密码被应用于几乎所有远程登录流量中,这现在几乎不是问题了。使用128位块密码进行加密,你无法发送少于16个字节(至少在另一端需要解码时是这样)。 - Damon
2
@camh 我知道你是在开玩笑,但为了维护 OP,禁用 Nagle 有时是 延迟 变量中的一种优化。 - Mateen Ulhaq
1
@camh,老实说,一开始我读 Mark 的建议时的理解是“在你确定需要延迟之前使用 NODELAY”,这恰恰是因为 Nagle 在我的脑海中是“优化”。在这种情况下,这肯定是一个模糊的建议。 - Dan Bechard

-4

TCP_CORK是TCP_NODELAY的相反。前者强制数据包积累延迟,而后者则禁用它。


21
TCP_CORK 不是 TCP_NODELAY 的相反选项。Nagle算法在等待返回ACK时聚合数据,而后者禁用了它;前者则基于缓冲区压力聚合数据。 - joshperry

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接