17

在写了一个关于 TCP_NODELAY 和 TCP_CORK 的答案后,我意识到我对 TCP_CORK 更精细点的了解一定是缺乏的,因为我不是 100% 清楚为什么 Linux 开发人员认为有必要引入一个新的 TCP_CORK 标志,而不是仅仅依赖于应用程序在适当的时候设置或清除现有的 TCP_NODELAY 标志。

特别是,如果我有一个 Linux 应用程序想要通过 TCP 流发送()一些小的/不连续的数据片段而不支付 200 毫秒 Nagle 延迟税,同时最小化需要发送的数据包数量它,我可以通过以下两种方式之一:

使用 TCP_CORK(伪代码):

int optval = 1;
setsockopt(sk, SOL_TCP, TCP_CORK, &optval, sizeof(int));   // put a cork in it
send(sk, ..);
send(sk, ..);
send(sk, ..);
optval = 0;
setsockopt(sk, SOL_TCP, TCP_CORK, &optval, sizeof(int));   // release the cork

或使用 TCP_NODELAY(伪代码):

int optval = 0;
setsockopt(sk, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof(int));   // turn on Nagle's
send(sk, ..);
send(sk, ..);
send(sk, ..);
optval = 1;
setsockopt(sk, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof(int));   // turn Nagle's back off

多年来,我一直在使用后一种技术并取得了不错的效果,而且它还具有可移植到非 Linux 操作系统的好处(尽管在 Linux 之外,您必须在关闭 Nagle 后再次调用 send() ,以便确保数据包立即发送并避免 Nagle 延迟——发送()'ing 零字节就足够了)。

现在 Linux 开发人员都是聪明人,所以我怀疑他们从来没有想到过 TCP_NODELAY 的上述用法。一定有他们觉得它不够的原因,这导致他们引入了一个新的/专有的 TCP_CORK 标志。任何人都可以解释那个原因是什么?

4

1 回答 1

22

你有两个问题:

  1. 在这个用例中,TCP_CORK 和 TCP_NODELAY 之间有什么显着区别吗?
  2. 一定有他们觉得它不够的原因,这导致他们引入了一个新的/专有的 TCP_CORK 标志。任何人都可以解释那个原因是什么?

首先查看此Stack Overflow Question中的答案,因为它们与该问题相关,因为该问题通常描述了两者之间的区别,而没有参考您的用例。

  • TCP_NODELAY ON意味着在你得到的那一刻发送数据(部分帧),无论你是否有足够的帧用于完整的网络数据包。
  • TCP_NODELAY OFF表示 Nagles 算法,表示当数据大于 MSS 时发送数据或等待接收确认后再发送较小的数据。
  • TCP_CORK ON表示不发送任何小于 MSS 的数据(部分帧),直到应用程序这么说或直到 200 毫秒后。
  • TCP_CORK OFF表示现在发送所有数据(部分帧)。

这意味着在第一个示例中的给定用例中,直到最后都不会发送部分帧,但在第二个示例中,将发送带有接收确认的部分帧。

同样是第一个示例中的最终发送,Nagle 的算法仍然适用于 uncorking 之后的部分帧,而在第二个示例中则不适用。

简短的版本是 TCP_NODELAY 发送在发送之前不会累积逻辑数据包,然后作为网络数据包发送,Nagle 的算法根据该算法执行,而 TCP_CORK 根据应用程序设置它执行。

这样做的一个副作用是 Nagle 的算法将在空闲连接上发送部分帧,而 TCP_CORK 不会。

此外,TCP_CORK 在 2.2 中被引入 Linux 内核(特别是 2.1.127,请参见此处),但在 2.5.71 之前,它与 TCP_NODELAY 互斥。例如,在 2.4 内核中,您可以使用其中一种,但在 2.6 中,您可以将两者结合起来,并且 TCP_CORK 在应用时将优先。

关于你的第二个问题。

引用 Linus Torvalds 的话

现在,TCP_CORK 基本上是我告诉大卫米勒我拒绝玩游戏以获得良好的数据包大小分布,并且我想要一种方法让应用程序只告诉操作系统:我想要大数据包,请等到你从我说你可以做大包。

基本上,TCP_CORK 是一种“anti-nagle”标志。这与“no-nagle”相反。

Linus 的另一个引用是关于 TCP_CORK 的使用如下

基本上,只要服务器知道其批量传输的模式,TCP_CORK 就很有用。对于任何类型的文件服务,这大约是 100% 的时间。

有关更多报价,请参阅 Sendfile 邮件列表讨论的链接。

总之,调用 writev 时除了 TCP_MAXSEG 和 MSGMORE 之外,TCP_CORK 是另一个工具,它允许用户空间中的应用程序对数据包大小分布进行更细粒度的控制。

参考文献和进一步阅读

于 2014-03-05T06:06:27.267 回答