在写完关于TCP_NODELAY和TCP_CORK的答案之后,我意识到我必须缺少对TCP_CORK的要点的了解,因为我尚不清楚100%为何Linux开发人员认为有必要引入一个新的TCP_CORK标志,而不是仅仅依靠应用程序在适当的时间设置或清除现有的TCP_NODELAY标志。
特别是,如果我有一个Linux应用程序想要通过TCP流send()一些小/非连续的数据片段,而无需支付200mS 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延迟- send()为零字节就足够了)。
现在,Linux开发人员很聪明,所以我怀疑他们对TCP_NODELAY的上述使用从未发生过。他们一定有某种理由感到不足,这导致他们引入了新的专有TCP_CORK标志。谁能解释这个原因是什么?
您有两个问题:
他们一定有某种理由感到不足,这导致他们引入了新的专有TCP_CORK标志。谁能解释这个原因是什么?
TCP_NODELAY ON 表示在您获取数据后立即发送数据(部分帧),而不管您是否有足够的帧容纳完整的网络数据包。
这意味着在第一个示例的给定用例中,直到结束都不会发送部分帧,但是在第二个示例中,将发送带有接收确认的部分帧。
同样,在您的第一个示例中,最后一次发送Nagle的算法仍然适用于拔瓶后的部分帧,而在第二个示例中则不适用。
简短的版本是TCP_NODELAY发送时不会在发送之前累积逻辑数据包,然后将其作为网络数据包,Nagle的算法根据算法进行操作,TCP_CORK根据应用程序对其进行设置。
这样做的副作用是Nagle的算法将在空闲连接上发送部分帧,而TCP_CORK不会。
另外,TCP_CORK在2.2(特别是2.1.127,请参阅此处)中引入了Linux内核,但是直到2.5.71,它与TCP_NODELAY互斥。例如,在2.4内核中,您可以使用其中之一,但在2.6中,您可以将两者结合使用,并且在应用TCP_CORK时会优先使用。
关于第二个问题。
引用莱纳斯·托瓦尔兹(Linus Torvalds)
现在,TCP_CORK基本上是告诉我大卫米勒,我拒绝玩游戏以具有良好的数据包大小分布,并且我想让应用程序仅告诉操作系统一种方法:我想要大数据包,请等待,直到从中获取足够的数据为止。我可以做成大包。 基本上,TCP_CORK是一种“ anti-nagle”标志。这是“无-”的反面。
现在,TCP_CORK基本上是告诉我大卫米勒,我拒绝玩游戏以具有良好的数据包大小分布,并且我想让应用程序仅告诉操作系统一种方法:我想要大数据包,请等待,直到从中获取足够的数据为止。我可以做成大包。
基本上,TCP_CORK是一种“ anti-nagle”标志。这是“无-”的反面。
Linus的另一句话是关于TCP_CORK的用法,如下所示
基本上,只要服务器知道其批量传输的模式,TCP_CORK就会很有用。使用任何类型的文件服务,这几乎都是100%的时间。
有关更多报价,请参见“ Sendfile邮件列表讨论”的链接。
总之,除了在调用writev时使用TCP_MAXSEG和MSGMORE之外,TCP_CORK是另一个工具,它允许用户空间中的应用程序对数据包大小分布进行更精细的控制。