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

61 sockets linux tcp

据我所知,他们都禁用了Nagle的算法.

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

the*_*heB 77

首先,并非他们都禁用了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)
Run Code Online (Sandbox Code Playgroud)

这将有助于telnet等应用程序.然而,等待ACK可能在发送流数据时增加等待时间.此外,如果接收器实现'延迟ACK策略',它将导致临时死锁情况.在这种情况下,禁用Nagle算法是一个更好的选择.

所以TCP_NODELAY用于禁用Nagle的算法.

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

在2.6内核之前,这两个选项都是互斥的.但是在后来的内核中,它们都可以一起存在.在这种情况下,TCP_CORK将获得更多的偏好.

参考:

  • 请记住Hussein Galal的答案,该答案阐明TCP_CORK在发送数据之前仅延迟最多200 ms. (5认同)
  • “这将有助于像 telnet 这样的应用程序。”?相反,事实恰恰相反。如果您按下某个键,这将延迟将您的按键发送到另一端,直到收到最后一次按键的 ACK。这会在按键和发送按键之间引入很高的延迟,我不知道在任何情况下都需要这样做。 (2认同)

小智 24

TCP_NODELAY

用于禁用nagle的算法来改进tcp/ip网络,并通过等待直到收到先前发送的数据的确认来发送累积的数据包来减少数据包的数量.

//来自tcp(7)手册:

TCP_CORK(或FreeBSD中的TCP_NOPUSH)

如果设置,请不要发送部分帧.再次清除该选项时,将发送所有排队的部分帧.这对于在调用sendfile(2)之前预先添加标头或用于吞吐量优化非常有用.正如目前实施的那样,TCP_CORK的输出时间上限为200毫秒.如果达到此上限,则自动发送排队的数据.自Linux 2.5.71起,此选项只能与TCP_NODELAY结合使用.此选项不应用于可移植的代码中.

  • 谢谢你指出许多指南已经完全错误,TCP_CORK只延迟了200ms(最大),它实际上不是一个可以阻塞直到删除的CORK. (5认同)

Mar*_*rkR 7

这是一个优化,所以像任何优化一样:

  1. 不要使用它
  2. 等到性能成为一个问题,然后确定套接字延迟肯定是它的原因,测试证明这肯定会解决它,这是修复它的最简单的方法,做到这一点.

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

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

  • Nagle本身就是一种优化,所以根据你的逻辑,你应该关掉它,只在需要时才把它打开:-) (40认同)
  • 如果实际发生在几年之后(有人不再实施它),我不会感到惊讶.大约30或40年前的主要问题是人们每秒大约2个字符在telnet上打字会为每个角色生成一个数据包.现在这几乎不是一个问题,因为bandwitdth要高得多,远程登录不会在流量方面扮演重要角色,并且阻塞密码无论如何都应用于几乎所有远程登录流量.使用128位块密码无法发送少于16个字节(无论如何要在另一端解码它). (5认同)
  • Nagle默认启用,您无需编写任何代码即可启用它,因此无论如何都会发生.不,如果您正在编写自己的TCP堆栈,如果您不需要实现Nagle,则不会这样做. (3认同)
  • @camh我知道你在开玩笑,但为了保护OP,禁用Nagle的行为*有时*是*延迟*变量的优化。 (2认同)