TCP 是如何保证可靠传输的?

进阶原理约 6 分钟读完

一句话回答

IP 层只负责尽力投递,TCP 在它之上用几套机制保证数据不丢、不错、不乱、不重:序列号和确认应答让发送方知道哪些数据已经送达;超时重传、快速重传和 SACK 补发丢失的数据;校验和发现损坏的数据;接收方按序号排序、去重。此外还有流量控制(滑动窗口)防止发送方把接收方淹没,拥塞控制防止把网络塞满。

详细解析

序列号和确认应答

TCP 给发送的每个字节都编了号。报文段的 seq 是这段数据第一个字节的序号;接收方回复的 ack 是它期望收到的下一个字节的序号,表示在这之前的数据都收到了。

文本
  发送方                                            接收方
     |--- seq = 1, len = 1000 ------------------------>|
     |<--------------------------------- ack = 1001 ---|
     |--- seq = 1001, len = 1000 --------------------->|
     |<--------------------------------- ack = 2001 ---|

这种确认是累积确认:收到 ack = 2001 就说明前 2000 个字节全部到了,所以中间某个 ACK 丢了也没关系。

重传机制

机制 触发条件 说明
超时重传 数据发出后,超过重传超时时间(RTO)还没收到确认 RTO 根据测得的往返时间(RTT)及其波动动态计算;每次超时重传后 RTO 翻倍
快速重传 连续收到 3 个重复的 ACK 接收方收到乱序的数据段时,会重复确认它还在等的序号。3 个重复 ACK 说明中间丢了一段、后面的已经到了,不必等超时,立即重传
选择性确认(SACK) 双方在握手时协商启用 接收方告诉发送方哪些不连续的数据段已经收到,发送方只重传缺失的部分;没有 SACK 时,发送方不知道后面哪些已经到了,可能重传对方已有的数据

校验和、排序和去重

  • 校验和:覆盖 TCP 首部、数据,以及由源 IP、目的 IP 等组成的伪首部。校验失败的报文段直接丢弃、不确认,之后由重传补上
  • 排序:数据段可能乱序到达,接收方按序号排好,再按顺序交给应用
  • 去重:重传可能让同一段数据到达两次,接收方根据序号丢弃重复的部分

TCP 的校验和只有 16 位,检错能力有限,对完整性要求高的场景还要依靠 TLS 等上层机制。

流量控制:滑动窗口

接收方的缓冲区是有限的。它在每个 ACK 里通告接收窗口 rwnd,也就是自己还能接收多少数据;发送方已发送但未确认的数据量不能超过这个值。下图中每格代表一段数据:

文本
          1   2   3   4   5   6   7   8   9   10  11  12
        +---+---+---+---+---+---+---+---+---+---+---+---+
        | A | A | A | B | B | B | C | C | C | D | D | D |
        +---+---+---+---+---+---+---+---+---+---+---+---+
                    |<---- window = 6 ----->|

A:已发送、已确认
B:已发送、未确认
C:未发送,但在窗口内,可以立即发送
D:未发送,超出窗口,要等窗口右移

收到 ack = 6(4、5 已确认)后,窗口左边界移到 6;如果接收方通告的窗口仍然是 6,右边界就移到 11,10 和 11 变成可发送。窗口就这样随着确认不断向右"滑动"。

如果接收方的应用读得慢、缓冲区满了,它会通告 rwnd = 0,发送方暂停发送。接收方腾出空间后会发送窗口更新,但这个报文可能丢失,双方就会互相等待。所以窗口为 0 时,发送方会定期发送窗口探测报文,询问最新的窗口大小。

拥塞控制和连接管理

面试官可能追问

流量控制和拥塞控制有什么区别?

流量控制照顾的是接收方的处理能力:窗口 rwnd 由接收方根据缓冲区的剩余空间在 ACK 中通告。拥塞控制照顾的是整个网络的承载能力:拥塞窗口 cwnd 由发送方根据丢包、延迟等信号自己估算。发送方实际能发送的数据量取两者中的较小值。

TCP 的队头阻塞是什么?

TCP 必须按顺序把数据交给应用。前面的数据段丢了,后面已经到达的数据只能留在接收缓冲区里,等丢失的段重传成功后才能一起交给应用。HTTP/2 在一个 TCP 连接上复用所有请求,一个包丢失会卡住全部请求;HTTP/3 改用 QUIC 解决了这个问题,见 HTTP 版本区别。

Nagle 算法是什么?

它把小数据包攒起来再发送:只要还有已发送但未确认的数据,新产生的小数据就先缓存,等收到 ACK 或者攒够一个 MSS 再发,避免网络上充斥只带几个字节的小包。代价是增加延迟,和接收方的延迟确认叠加时更明显。游戏、实时交互这类对延迟敏感的场景,可以用 TCP_NODELAY 选项关闭它,Node.js 中对应 socket.setNoDelay(true)。

易错点

  • ack 是"期望收到的下一个字节的序号",不是"已收到的最后一个字节的序号"
  • RTO 不是固定值:它根据 RTT 动态计算,每次超时重传后还会翻倍
  • TCP 的可靠只到传输层:数据进了对方的接收缓冲区,不代表对方应用已经处理成功,业务上的"必达"还要靠应用层确认

AI 模拟面试官

用自己的话回答,AI 对照参考答案打分、指出遗漏,再追问,最多 3 轮

登录后就可以和 AI 面试官对练,面试记录也会保存下来。登录

这道题你掌握了吗?

选一个最接近的状态,没掌握的题会出现在"我的进度 · 待复习"里。

学习记录暂存在本机浏览器。登录后自动同步到账号,换设备也能看到。