本文目录导读:
TCP的保序性(即保证数据按发送顺序到达接收端)是通过序列号(Sequence Number)、确认应答(ACK)、重传机制和滑动窗口协议共同实现的,其核心原理是:每个数据字节都被赋予一个递增的序列号,接收端根据这个序列号进行排序和重组,即使数据包乱序到达,也能恢复原始顺序。
具体机制如下:
序列号(Sequence Number)
- TCP将发送的每个字节都编号,初始序列号(ISN)在建立连接时随机生成,随后每个数据包都携带其第一个字节的序列号。
- 关键作用:接收端收到数据包后,根据序列号知道它属于数据流的哪个位置,从而进行排序。
发送端的确认应答(ACK)
- 接收端收到数据后,会发送ACK确认,告知发送端“我已经收到了序列号X之前的所有数据”。
- 发送端维护一个发送缓冲区,未被确认的数据会一直保留,等待重传。
接收端排序与缓冲区
- 接收端有接收缓冲区,当收到乱序的数据包(例如序列号1000的数据先到,而序列号500的还没到),接收端不会丢弃它,而是将其暂存在缓冲区中,等待缺失的数据到来。
- 一旦缺失的数据到达(例如序列号500的数据),接收端就会把缓冲区中连续的数据一起递交上层应用。
重传机制保证不丢包
- 超时重传:如果发送端在超时时间内未收到某个数据包的ACK(表明该包可能丢失),就会重新发送该包及其之后的所有数据(取决于实现)。
- 快速重传:如果发送端连续收到3个“重复ACK”(即对同一个序列号的ACK多次),则立即推断该序列号后的数据包丢失,无需等待超时,直接重传。
滑动窗口流量控制
- 接收端通过“窗口大小”字段告知发送端自己的缓冲区剩余容量,发送端只能发送窗口允许范围内的数据,避免接收端缓冲区溢出。
- 滑动窗口也保证了数据包虽然可以同时发送多个,但序号必须是连续的,如果发生乱序,接收端会暂时阻塞应用层的读取,直到序列号连续。
典型场景:数据乱序到达
假设应用层发送了 3 个数据包:[seq=1]、[seq=2]、[seq=3]。
- 乱序到达:接收端先收到
[seq=3],[seq=1]。- 接收端将
[seq=3]放入缓冲区,但不会交给应用层(因为缺少 seq=1,2)。 - 随后收到
[seq=1],放入缓冲区,但仍然缺少 seq=2,继续等待。
- 接收端将
- 重传或补全:
[seq=2]丢失,发送端会通过超时或快速重传重新发送 seq=2。 - 连续性恢复:收到 seq=2 后,缓冲区中的
seq=1,2,3连续,接收端一次性将这三个数据包按顺序交给应用层。
TCP保序的三大支柱
| 机制 | 作用 |
|---|---|
| 序列号 | 标记每个字节的位置,作为排序的唯一依据 |
| 接收端缓冲区 | 暂存乱序到达的数据,等待缺失数据补齐 |
| 重传机制 | 确保即使丢包,也能恢复丢失的数据,保证顺序完整性 |
最终效果:无论底层IP网络如何乱序、丢包、重复,TCP都会向上层应用提供一个无差错、按序、不重复、不丢失的字节流。