TCP可靠传输

← 返回 TCP | ← 返回 MOC


TCP 保证数据不丢、不乱序,靠的是三个机制:序号确认、超时重传、滑动窗口

序号与确认

TCP 把数据看成一串连续的字节,每个字节都有编号。发送方发出一段数据,接收方回一个 ACK 告诉发送方”这个序号之前的我都收到了”。

没收到 ACK,发送方就重传。

滑动窗口

一包一包等 ACK 太慢,滑动窗口允许发送方连续发多包,不用等每一包的 ACK。

窗口大小由接收方决定——接收方在 ACK 里告诉发送方自己的缓冲区还剩多少,发送方不能超过这个量。这也是流量控制的基础,详见 TCP流量与拥塞控制

TCP 的滑动窗口和数据链路层的滑动窗口原理相同,区别在于:

  • TCP 按字节确认,不是按帧
  • TCP 窗口大小动态变化,受流量控制和拥塞控制双重约束

超时重传

发送方发出数据后启动计时器,超时还没收到 ACK 就重传。

计时器时间(RTO)不是固定的,TCP 会根据网络往返时间(RTT)动态调整,网络慢就等久一点。

快重传

超时重传要等计时器到期,反应慢。快重传是一个优化:

接收方收到乱序的包时,每次都重复发同一个 ACK(催促发送方补那个缺的包)。发送方连续收到 3 个重复 ACK,不等超时,立刻重传那个包。

粘包问题

TCP 是字节流,也就是一段一段的数据连续写入缓冲区,没有天然的边界。发送方发了两条消息,接收方可能一次收到一条半,也可能两条拼在一起收到。

UDP 不会有这个问题,因为 UDP 面向报文,一发一收天然有边界。

解决方法由应用层处理,常见三种:

  • 固定长度:每条消息固定 N 字节,不够补齐
  • 分隔符:消息之间加特殊字符(如 \n),接收方按分隔符切割
  • 长度前缀:消息头部写明数据长度,接收方先读长度再读数据

如果你正在跟随梳理, 返回 TCP←