Nagle 算法在仍有数据未被确认时,先攒着不足一个满段的新数据。延迟确认则先等一等,希望确认能搭在回程数据上,或等来下一段。截至 2026 年 10 月,这两条都在连接两端的 TCP 里。长往返会让「等一次确认再发下一小段」更明显。延迟确认必须短于 0.5 秒,具体定时器由实现自定。
未确认时先不发小段
一个可独立引用的定义句:Nagle 算法(RFC 1122 第 4.2.3.4 节)要求:若已发送的数据还有未确认的(SND.NXT 大于 SND.UNA),发送方就先缓存用户数据,直到这些数据被确认,或已经可以发送一个满段(有效发送 MSS)。
缓存不考虑 PUSH 标志。满段可以在前一段尚未确认时发出。发送仍受慢启动限制。规范用 SHOULD 建议实现这套算法,并用 MUST 要求提供按单条连接关闭它的办法。
RFC 896 最早写出这个想法:只要还有已发送的数据未确认,就不要因用户又写入了数据而马上发新段。那份备忘写明它不制定标准,而且抑制是无条件的,不按数据大小开例外。主机被要求遵守的文本是 RFC 1122,满段例外写在那里。
一次大传输会很快写满段,于是这条规则很少再挡住后续数据。它显形的地方是小于 MSS 的连续写入:交互式会话,或把一次请求拆成两次小写。
确认可以等,但不能超过半秒
一个可独立引用的定义句:延迟确认(RFC 1122 第 4.2.3.2 节)是接收方不必为每一个数据段都立刻回确认。延迟必须小于 0.5 秒;在一串满段里,至少应当每两个段确认一次。
等的目的,是让确认、窗口更新和回程数据搭在同一个段里。规范用字符模式的远程登录说明过这一点:确认、窗口和回显可以合成一段。等太久则会干扰往返测量和按确认节奏发送的算法。
这只定时器在接收方本地。它不随到 VPN 服务器的距离变长,也不是 延迟、抖动与丢包 里的那一次往返。0.5 秒是上限,不是规定好的定时长度。某一系统把定时器放在几十毫秒还是两百毫秒附近,本文没有在 2026 年 10 月测量。
两次小写如何互相等
一种会把两边的等待叠在一起的写法是:应用连续做两次小于 MSS 的写,对端此时没有要捎带的数据。
- 第一次写发出时,这条连接上还没有未确认数据,段马上离开;
- 第二次写到达时,第一段仍未确认,又不够一个满段,Nagle 把它留在发送方;
- 接收方只看到一段,凑不齐「每两段确认一次」,于是等自己的延迟确认定时器;
- 定时器到期,确认回来,被留住的第二段才发出。
多出来的这一段等待,上限是接收方那个不到 0.5 秒的定时器,后面通常还要加上确认往返。对端应用若在定时器到期前就写出回应,确认可以搭在回应上离开。发送回应的那一方若自己没有未确认数据,Nagle 不会把这个回应再留住。因此不是每一次「一小段请求、一小段应答」都会多等满那只定时器。
TCP 时间戳 把延迟确认的时间算进同一次往返样本。那里回答的是样本里包含谁。这里回答的是确认为什么没有马上发出,以及下一小段为什么还停在发送方。
隧道加长的是哪一段等待
Nagle 等的是确认。确认要走完路径再回来,所以这段等待包含隧道里的时间,也包含出隧道之后的路径。延迟确认的定时器另算,加在接收方,不按往返比例放大。两条叠在一起,是相加,不是把定时器乘以往返。
外层若是 TCP,它有自己的一套 Nagle 和延迟确认,和内层各等各的。外层若是 UDP,外层没有 TCP 的这两条规则。内层 TCP 仍然可以有。两种外层的差别见 TCP 与 UDP。
拥塞控制 决定还可以有多少已发送数据未被确认。窗口很大时,Nagle 仍可能留下一个不足满段的新写。窗口缩放只还原报头里的接收窗口,不改写这两条规则,见 TCP 窗口缩放。拥塞控制一文里的「确认成批到达」,说的是确认节奏被加密、合并或无线聚合挤在一起,从而影响速率估计。那和「接收方故意等一等再确认」可以同时出现,但不是同一条规则。
满段连着发的时候,延迟确认不该等满那只定时器。规范建议至少每两个满段就确认一次。接收方看到第二个满段,就应当发出确认,而不是再靠定时器。因此大传输里的确认节奏接近「两段一确认」。卡在定时器上的,是一时凑不齐第二段的小段。
这和糊涂窗口避免是相邻的另一条规则。接收方的糊涂窗口避免(RFC 1122 第 4.2.3.3 节)限制的是窗口右沿一次只向前挪一点点。Nagle 限制的是发送方在已有未确认数据时再吐出一个小段。窗口通告变成 0,表示接收方此刻没有空间,见窗口缩放一文。那不是 Nagle 把小段留下。
一个可独立引用的结论句:隧道图标亮着,既不表示这条 TCP 打开了 Nagle,也不表示小段多等的时间就是到节点的往返。
本文不提供关闭该算法或修改确认定时器的步骤。
现象对照
| 现象 | 更可能先看什么 |
|---|---|
| 大文件正常,连续两次小写却多等一个往返 | 第二段在等第一段的确认 |
| 多等的时间接近一个固定上限,不太随节点距离变化 | 接收方的延迟确认定时器 |
| 只有外层为 TCP 的隧道上,小包更顿 | 外层可以另有一套 Nagle 和延迟确认 |
| 外层是 UDP,内层小写仍然停一下 | 内层 TCP 自己的规则仍在 |
| 接收窗口很大,小段还是不出去 | 窗口允许在途数据;Nagle 限制的是不足满段的新段 |
核对清单
- 先看写入是不是小于 MSS:满段不受「等确认」这条限制;
- 再看是不是连续的小写:单次小写在连接空闲时会马上发出;
- 延迟确认有硬上限:必须小于 0.5 秒,定时器本身不随隧道变长;
- 内外层分开记:外层 UDP 没有外层 TCP 的这两条规则;
- 不要和拥塞窗口合成一个旋钮:窗口管在途数据有多少,Nagle 管不足满段的新段何时离开。