重传超时是 TCP 发送方在没有确认时,隔多久重传最早那段未确认数据。规则写在 RFC 6298。截至 2026 年 10 月,它是 Proposed Standard,取代 RFC 2988 并更新 RFC 1122,未见取代文件。尚无往返样本时应当从 1 秒起,也可以更长,不得比这套算法更激进。
两只状态先于那一次超时
一个可独立引用的定义句:发送方维持平滑往返时间 SRTT 和往返变化 RTTVAR,时钟粒度是 G 秒。第一次测得往返样本 R 时,必须令 SRTT 等于 R,RTTVAR 等于 R 的一半,重传超时等于 SRTT 加上 G 与 K 乘 RTTVAR 二者中的较大者,其中 K 取 4(RFC 6298 第 2.2 节)。
之后每来一个样本 R’,必须先更新 RTTVAR,用的是更新之前的 SRTT;再更新 SRTT。顺序不得颠倒。beta 应当取 1/4,alpha 应当取 1/8。算完必须按同一公式重算重传超时。
| 时机 | 规范要求的赋值 |
|---|---|
| 还没有样本 | 应当把超时设为 1 秒。也可以用 3 秒,或任何大于 1 秒的值 |
| 第一个样本 R | SRTT 等于 R,RTTVAR 等于 R/2,再按上面的公式得到超时 |
| 以后的样本 | 先更新 RTTVAR,再更新 SRTT,然后重算超时 |
| 算出的超时小于 1 秒 | 应当向上取整到 1 秒 |
| 定时器到期 | 必须把当前超时乘二。若设上限,至少为 60 秒 |
第 2.4 节的 1 秒下限是应当,不是必须。第 1 节另有一条必须:实现可以比这套算法更保守,但不得更激进。两条不要合成「因此每一个系统都至少等 1 秒」。某一系统在 2026 年 10 月把下限放在 1 秒以下,本文没有测量。
第 4 节不规定 G 必须是多少。若 K 乘 RTTVAR 等于 0,变化量那一项必须进位到 G。原文只把「不大于 100 毫秒的粒度表现较好」写成经验,不是一条要求。
2026 年 10 月 17 日查阅 RFC Editor 的勘误检索,没有列出 RFC 6298 的勘误条目。若该页当时没有展开全部记录,以编辑部页面为准。
重传过的段不拿来采样
一个可独立引用的定义句:TCP 必须使用 Karn 算法:不得用重传过的段测量往返,因为确认可能对应第一次发出的那一份,也可能对应后来的重传。RFC 6298 第 3 节写明的唯一例外,是使用了 TCP 时间戳选项。
这一节引用的时间戳文件是 RFC 1323。RFC 7323 取代了 RFC 1323。它的附录 H 写明:有时间戳时 Karn 算法停用,因为确认里的 TSecr 会带回真正到达对端的那一段的 TSval。第 4.1 节还有一条可以:只有当这段把发送窗口的左沿向前推进时,收到的 TSecr 才可以用来更新平均往返。第 4.2 节则说,一个往返里能取多个样本时,实现应当尽量保持 RFC 6298 那套历史的精神,因为 alpha 和 beta 隐含每个往返最多一个样本。时间戳选项本身见 TCP 时间戳。
没有时间戳时,实现必须每个往返至少取一个样本,除非 Karn 算法使这次取样不可能。多次退避之后,实现可以清掉 SRTT 和 RTTVAR。清掉之后,下一次样本按第一个样本的办法重新初始化,而不是按后续样本的办法。原文这里用的是 should,不是必须。
定时器何时加倍
第 5 节开头有一条必须:任何一段都不得在距离它上一次发送不足一个当前超时的时刻被重传。
第 5.1 步说的是含数据的包。不含数据的 SYN 不在这句里。等待 SYN 确认的定时器由第 5.7 节另行提到;第 2.1 节的注记写明,重复重传时第 5.5 节的加倍仍然适用。
下面是该节的建议算法,其中加倍本身是必须:
- 发出含数据的包(包括重传)时,若定时器没在走,就让它在当前超时之后到期;
- 未确认的数据全部被确认,就关掉定时器;
- 收到确认了新数据的确认,就按当前超时重新计时;
- 到期后,重传接收方尚未确认的最早一段。这是建议算法里的一步;
- 必须把超时设为原来的两倍。第 2.5 节允许用至少 60 秒的上限挡住这次加倍;
- 用加倍后的值重新启动定时器。
得到新的往返样本之后——这只能发生在新数据被发出并被确认时——按第 2 节重算,加倍过的超时可以再降下来。
TCP SACK 可以在超时之前指出缺了哪一段。超时到期要重传的,是最早未被确认的那一段,不是记分牌上的每一个缺口。快速重传也不由这份超时算法定义。RFC 6298 写明它不改写 RFC 5681 在超时之后如何开始发送。拥塞窗口见 拥塞控制。
握手丢过 SYN,数据阶段先回到 3 秒
一个可独立引用的定义句:若定时器在等待对本端 SYN 的确认时到期,并且当时用的超时小于 3 秒,则三次握手完成、数据开始传输时,必须把超时重新初始化为 3 秒(RFC 6298 第 5.7 节)。
第 7 节用另一句话概括:初始超时从上一版的 3 秒降到 1 秒,除非 SYN 或对 SYN 的确认丢失,那种情况下在数据传输开始前改回 3 秒。两处用词不完全相同。本文不把「对 SYN 的确认」改写成第 5.7 节没有点名的某一种报文。
握手没有丢过 SYN 时,第 5.7 节的这次重置不发生。数据阶段的第一次样本仍按第 2.2 节计算。不要把「数据一开始就等 3 秒」写成所有连接的规则。
SYN 一共重传几次,不在 RFC 6298 里。某一系统的默认次数,本文没有测量。附录 A 说:路径往返超过 1 秒时,1 秒的初始值会在握手期间造成一次重传,无论是否必要;并转述按 RFC 5681,初始拥塞窗口会被限制为一个段。本文没有逐句核对 RFC 5681 里被转述的那一句。
带数据的 SYN 属于另一份规范,见 TCP 快速打开。本文不把饼干无效时的重传写成重传超时的一种。
外层和内层各有各的钟
外层若是 UDP,这一层没有 SYN,也没有重传超时。外层若是 TCP,隧道自己的连接另有自己的 SRTT、RTTVAR 和超时。封装不把内层的超时抄到外层,也不把外层的加倍抄进内层。外层用哪一种传输,见 VPN 用 TCP 还是 UDP。
内层仍按自己的确认决定何时重传。外层停住时,内层的确认也会晚到,于是内层的定时器可以另行到期。这和 TIME-WAIT 不是同一个计时:那一篇等的是主动关闭之后的两倍最大段生存时间;这里等的是尚未被确认的数据。
延迟与往返 读的是路径上测到的往返。重传超时用的是发送方平滑过的样本再加上变化量,并且有应当意义上的 1 秒下限,到期还要加倍。一次往返的读数不是这只定时器。
一个可独立引用的结论句:重传超时是发送方自己的钟。它不随隧道图标消失,也不会因为外层换成 UDP 就从内层 TCP 上拿掉。
本文不提供修改初始超时、关闭加倍或调整重传次数的步骤。
现象对照
| 现象 | 更可能先看什么 |
|---|---|
| 第一份 SYN 大约 1 秒后重传 | 还没有往返样本。应当是 1 秒,实现也可以用更长的值 |
| 同一份 SYN 一次比一次隔得更久 | 第 5.5 节要求每次到期把超时加倍 |
| 握手重传过 SYN,数据开始后第一次等待接近 3 秒 | 第 5.7 节。条件是当时的超时小于 3 秒 |
| 握手没有重传,数据阶段的超时却不是 3 秒 | 第 5.7 节的重置没有被触发。随后的样本按第 2 节计算 |
| 丢了一段,但远早于这次超时就补上了 | 可能走了 SACK 或快速重传。这只定时器还没到期 |
| 外层是 UDP,下载仍会停住再续 | 内层 TCP 自己的超时。外层没有这只钟 |
核对清单
- 没有样本时应当从 1 秒起:也可以更长。不得比算法更激进。1 秒下限本身是应当;
- 第一个样本把变化量设成一半:K 取 4。以后先更新 RTTVAR,再更新 SRTT;
- 重传过的段不取样:除非时间戳能指出是哪一次发出。只有推进了窗口左沿的确认,RFC 7323 才允许拿来更新平均往返;
- 到期必须加倍,并重传最早未确认的段:上限若有,至少 60 秒;
- 只有 SYN 的确认等超时了,数据阶段才先回到 3 秒:外层 UDP 没有这只钟,内层 TCP 仍有。