TCP 可靠传输
TCP 在不可靠的 IP 层之上建立一种可靠数据传输服务。TCP 提供的可靠数据传输服务保证接收方从缓存区读出的字节流与发送方发出的字节流完全一样。TCP 使用了检验、序号、确认和重传等机制来达到这一目的。其中,TCP 的检验机制与 UDP 一样(5.2.2)。
真题考过 TCP 的确认机制与序号、确认号的含义(2011、2012、2013)。这一节是第 3 章滑动窗口的延续:原理相同(3.4.2),不同的是 TCP 按字节编号、确认号表示期望的下一个字节。本页的错题问的是重传的上限:重传的数据量不会超过发送窗口。
机制
序号
TCP 首部的序号字段用来保证数据能有序提交给应用层,TCP 把数据视为一个无结构但有序的字节流,序号建立在传送的字节流之上,而不建立在报文段之上。
TCP 连接传送的数据流中的每个字节都编上一个序号。序号字段的值是指本报文段所发送的数据的第一个字节的序号。例如,A 和 B 之间建立了一条 TCP 连接,A 的发送缓存区中共有 10B,序号从 0 开始标号,第一个报文段包含第 0~2 个字节,则该 TCP 报文段的序号是 0,第二个报文段的序号是 3。
| 报文段 | 第一个 | 第二个 | 第三个 | 第四个 |
|---|---|---|---|---|
| 字节 | 0~2 | 3~5 | 6~7 | 8~9 |
| 序号字段 | 0 | 3 | 6 | 8 |
确认
TCP 首部的确认号是期望收到对方的下一个报文段的数据的第一个字节的序号。在上例中,若接收方 B 已收到第一个报文段的数据,此时 B 希望收到的下一个报文段的数据是从第 3 个字节开始的,则 B 发送给 A 的报文段中的确认号字段应为 3。发送方缓存区会继续存储那些已发送但未收到确认的报文段,以便在需要时重传。
TCP 默认使用累积确认,即 TCP 只确认数据流中至第一个丢失字节为止的字节,这样可以减小传输开销。接收方可在合适的时候发送确认,也可在自己有数据要发送时将确认信息顺便捎带上(捎带确认)。例如,在上例中,接收方 B 收到了 A 发送的包含字节 0~2 及字节 6~7 的报文段。由于某种原因,B 还未收到字节 3~5 的报文段,此时 B 仍在等待字节 3(和其后面的字节),因此 B 到 A 的下一个报文段将确认号字段置为 3。
重传
有两种事件会导致 TCP 对报文段进行重传:超时和冗余 ACK。
(1)超时。TCP 每发送一个报文段,就对这个报文段设置一个超时计时器。计时器设置的重传时间到期但还未收到确认时,就要重传这一报文段。
因为 TCP 的下层是互联网环境,IP 数据报所选择的路由变化很大,所以传输层的往返时延的方差也很大。为了计算超时计时器的重传时间,TCP 采用一种自适应算法,它记录一个报文段发出的时间,以及收到相应确认的时间,这两个时间之差称为报文段的往返时间(Round-Trip Time,RTT)。TCP 维护了 RTT 的一个加权平均往返时间 RTTS,它会随新测量 RTT 样本值的变化而变化。显然,超时计时器设置的超时重传时间(Retransmission Time-Out,RTO)应略大于 RTTS,但也不能大太多,否则当报文段丢失时,TCP 不能很快重传,导致数据传输时延大。
(2)冗余 ACK(冗余确认)。超时触发重传存在的一个问题是超时周期往往太长。所幸的是,发送方通常可在超时事件发生之前通过注意所谓的冗余 ACK 来较好地检测丢包情况。冗余 ACK 就是再次确认某个报文段的 ACK,而发送方先前已经收到过该报文段的确认。
例如,发送方 A 发送了序号为 1、2、3、4、5 的 TCP 报文段,其中 2 号报文段在链路中丢失,它无法到达接收方 B。因此 3、4、5 号报文段对于 B 来说就成了失序报文段。TCP 规定每当比期望序号大的失序报文段到达时,就发送一个冗余 ACK,指明下一个期待字节的序号。
sequenceDiagram participant A as 发送方 A participant B as 接收方 B A->>B: 报文段 1 B-->>A: 确认 1 号,期望 2 号 A-xB: 报文段 2(丢失) A->>B: 报文段 3 B-->>A: 冗余 ACK:期望 2 号(第 1 个) A->>B: 报文段 4 B-->>A: 冗余 ACK:期望 2 号(第 2 个) A->>B: 报文段 5 B-->>A: 冗余 ACK:期望 2 号(第 3 个) Note over A: 收到 3 个冗余 ACK,不等超时,立即重传 2 号 A->>B: 报文段 2(快速重传)
在本例中,3、4、5 号报文段到达 B,但它们不是 B 所期望收到的下一个报文段,于是 B 就发送 3 个对 1 号报文段的冗余 ACK,表示自己期望接收 2 号报文段。TCP 规定当发送方收到对同一个报文段的 3 个冗余 ACK 时,就可以认为跟在这个被确认报文段之后的报文段已经丢失。 就前面的例子而言,当 A 收到对于 1 号报文段的 3 个冗余 ACK 时,它可以认为 2 号报文段已经丢失,这时发送方 A 可以立即对 2 号报文段执行重传,这种技术通常称为快速重传。冗余 ACK 还被用在拥塞控制中(5.3.6)。
边界
错题复盘:重传的数据量最多等于发送窗口的大小
王道 5.3.7 第 16 题:TCP 的滑动窗口协议中,规定重传分组的数量最多可以(A. 是任意的 B. 1 个 C. 大于滑动窗口的大小 D. 等于滑动窗口的大小)。答案 D。
TCP 滑动窗口协议中发送方滑动窗口的大小规定了发送方最多能够传送的分组数量,只有窗口滑动了,才能往后继续发送。分组重传的最大值也是发送方能发送数据的最大值,因而重传分组的数量最多也不能超过滑动窗口的大小。
需要重传的只能是”已发送但未被确认”的数据,而这部分数据一定落在发送窗口内——窗口外的要么已被确认,要么还没发过。所以重传量的上界就是窗口本身。选 B 是把”超时后通常只重传最早的那一个报文段”当成了规定。
确认号是期望的下一个字节,不是最后收到的字节。 这与第 3 章王道的 GBN 口径(ACK
累积确认只确认到第一个缺口。 缺口后面已经收到的字节,确认号不会越过缺口去确认它们。
发送方收到 3 个冗余 ACK,才触发快速重传。 3 个冗余 ACK 指在首次确认之外又重复收到 3 次,即对同一序号共收到 4 个 ACK。
RTO 应略大于 RTTS。 太小会导致不必要的重传,太大则丢包后迟迟不重传。
口径差异:TCP 的计时器与重传方式
教材口径:TCP 每发送一个报文段,就对这个报文段设置一个超时计时器;超时重传时间应略大于加权平均往返时间 RTTS。
标准口径:实际的 TCP 实现通常只为最早的未确认报文段维护一个重传计时器(RFC 6298),RTO 按
计算,每次超时后 RTO 加倍。TCP 的累积确认像 GBN,但接收方会缓存失序到达的报文段、发送方超时后通常只重传一个报文段,又像 SR;选择确认(SACK)选项还能把缺口之后已收到的数据块告诉发送方。 考试按教材口径作答:若问”TCP 更接近哪种协议”,按王道的讲法作答,不要自行引入 SACK。
对照速查
| 说法 | 对错 |
|---|---|
| TCP 的序号建立在报文段之上 | ❌(建立在字节流之上) |
| TCP 默认使用累积确认 | ✅ |
| 收到字节 0~2 和 6~7,确认号为 8 | ❌(仍为 3) |
| 确认可以捎带在对方发送的数据报文段中 | ✅ |
| 超时和冗余 ACK 都会触发重传 | ✅ |
| 收到 1 个冗余 ACK 就立即重传 | ❌(3 个) |
| RTO 应该比 RTTS 小一些 | ❌(略大于) |
| 重传的分组数量最多等于滑动窗口的大小 | ✅ |
| 已发送但未收到确认的数据要保留在发送缓存中 | ✅ |
考点
- 四种机制:检验、序号、确认、重传
- 序号按字节;确认号 = 期望的下一个字节;累积确认、捎带确认(2011、2012、2013)
- 超时重传:RTT、RTTS、RTO 略大于 RTTS
- 3 个冗余 ACK → 快速重传
- 重传量 ≤ 发送窗口
链接
- 🏠 返回总览:计算机网络第 5 章:传输层总览
- ⬅️ 上一节:5.3.3 TCP 连接管理
- ➡️ 下一节:5.3.5 TCP 流量控制
- 🔗 3.4.2 可靠传输机制(GBN、SR 的原理)
- 📖 名词库:第 5 章名词库