Chapter 3-4:TCP 可靠传输、流量控制与连接管理学习指南

Chapter 3-4:TCP 可靠传输、流量控制与连接管理学习指南

这份课件主体内容是传输层中的 TCP。如果前几节 rdt、GBN、SR 讨论的是“可靠传输的原理模型”,这一节就是把这些思想落到真实 Internet 传输层协议 TCP 上。

TCP 要解决的问题是:

在 IP 本身不可靠的基础上,如何为应用进程提供一种可靠、按序、面向连接、可控速率的字节流传输服务?


0. 本节核心主线

TCP 的核心能力可以压缩成一条链:


❗ 本节核心结论:
TCP 不是让网络层变可靠,而是在端系统之间维护序号、ACK、窗口、定时器、连接状态等机制,把不可靠的 IP 服务包装成可靠字节流。

1. TCP 的整体特性

TCP 是 Transmission Control Protocol,传输控制协议。

它的典型特征包括:

特征 含义
面向连接 通信前要建立连接,通信后要释放连接
可靠传输 丢失的数据可以被检测并重传
按序交付 应用层看到的是按序字节流
字节流服务 TCP 不保留应用层 message 边界
全双工 双方可以同时发送和接收
流量控制 避免发送方淹没接收方
拥塞控制 避免发送方压垮网络,后续章节重点讲

1.1 TCP 是字节流,不是报文流

这是最重要的概念之一。

TCP 面向的是 byte stream。应用层调用两次 send(),接收方不一定对应两次 recv();应用层一次发送的大数据,也可能被 TCP 拆成多个 segment。

所以:

1
TCP 可靠的是字节流顺序,不是应用层报文边界。

❗ 本节核心结论:
TCP 不承诺“你 send 几次,对方就 recv 几次”;TCP 只承诺字节按序、可靠地进入接收方字节流。

2. TCP Segment 结构

TCP 传输的基本单位是 TCP segment。它由 TCP 首部和应用层数据组成。

关键字段如下:

字段 作用
Source Port / Dest Port 标识两端应用进程
Sequence Number 本 segment 中第一个数据字节的编号
Acknowledgement Number 期望收到的下一个字节编号
Receive Window, rwnd 接收方还能接收多少字节
Checksum 检测 TCP segment 是否损坏
SYN 建立连接
FIN 关闭连接
RST 异常重置连接

2.1 TCP 序号不是“第几个 segment”

TCP 的 sequence number 是 字节序号,不是 segment 序号。

假设一个 segment 的 Seq = 1000,携带 500 字节数据,那么下一个 segment 的序号通常是:

1
Seq = 1500

而不是:

1
Seq = 1001

❗ 本节核心结论:
TCP 的序号按字节计数。一个 segment 携带多少字节,下一个序号就增加多少。

3. Sequence Number 与 ACK Number

3.1 Sequence Number

TCP 的 sequence number 表示:

本 segment 中第一个数据字节在整个字节流中的编号。

例如:

1
Seq = 42

表示这个 segment 的第一个数据字节编号是 42。

3.2 ACK Number

TCP 的 acknowledgement number 表示:

接收方期望收到的下一个字节编号。

例如:

1
ACK = 100

不是说“我收到了第 100 号字节”,而是说:

1
2
100 之前的字节我已经按序收到了;
我现在期待从 100 开始的字节。

3.3 TCP 使用累计确认

TCP 的 ACK 是 cumulative ACK,累计确认

ACK = n 的含义是:

1
2
n 之前的连续字节都已经按序收到;
下一个期待的字节是 n。

所以 ACK 不是单独确认某个 segment,而是确认一段连续字节流。


❗ 本节核心结论:
TCP 的 ACK Number 表示“下一个期待的字节编号”,而不是“最后收到的字节编号”。

4. RTT 与超时机制

TCP 需要判断:

等多久还没收到 ACK,才认为可能丢包,需要重传?

这个等待时间不能随便定。太短会导致过早重传,太长会导致恢复丢包太慢。

4.1 RTT

RTT 全称是 Round-Trip Time,往返时间。

在 TCP 中,它大致表示:

1
2
3
4
5
一个 segment 发出

对应 ACK 返回

中间经历的时间

4.2 SampleRTT

SampleRTT 是某一次实际测量值:

1
SampleRTT = segment 发出到收到对应 ACK 的时间

但重传过的 segment 通常不用于 SampleRTT 测量,因为发送方无法判断 ACK 对应的是原始 segment 还是重传 segment。

4.3 EstimatedRTT

TCP 不会只用一次 SampleRTT 直接决定超时,而是使用指数加权移动平均:

1
EstimatedRTT = (1 - α) * EstimatedRTT + α * SampleRTT

课件中常用:

1
α = 0.125

这表示:新样本有影响,但不会完全覆盖历史估计。

4.4 DevRTT 与 TimeoutInterval

只知道平均 RTT 还不够,因为网络延迟会波动。

TCP 用 DevRTT 估计 RTT 的波动程度,并设置:

1
TimeoutInterval = EstimatedRTT + 4 * DevRTT

也就是说:

1
超时时间 = 平均 RTT 估计 + 安全余量

❗ 本节核心结论:
TimeoutInterval 不能简单等于 EstimatedRTT;它必须考虑 RTT 波动,否则会频繁误判丢包。

5. TCP 可靠数据传输

TCP 在 IP 的不可靠服务上实现可靠传输,主要依靠:

  • sequence number;
  • cumulative ACK;
  • timeout;
  • retransmission;
  • duplicate ACK;
  • fast retransmit。

简化版 TCP 发送方主要处理三类事件:

事件 发送方动作
应用层交来数据 创建 segment,填入 NextSeqNum,发送给 IP,必要时启动定时器
Timeout 重传最早未确认 segment,重新启动定时器
收到 ACK 如果 ACK 确认了新数据,移动 SendBase;若仍有未确认数据则重启定时器,否则停止定时器

5.1 TCP 像 GBN 还是 SR?

TCP 不能简单等同于 GBN 或 SR,它混合了二者思想。

机制 TCP 表现 更像谁
ACK 累计确认 GBN
定时器 通常使用单个重传定时器 GBN
超时重传 重传最早未确认 segment 更接近 SR 的选择性思想
乱序段处理 标准不强制必须缓存或丢弃 取决于实现

所以更准确的说法是:

TCP 借鉴了 GBN 的累计确认和定时器思想,也借鉴了 SR 的选择性重传倾向,但它不是二者的简单复制。


6. 快速重传 Fast Retransmit

6.1 什么是重复 ACK?

如果接收方一直发送同一个 ACK,说明它一直在等待同一个字节位置的数据。

例如接收方期待字节 100,但后面收到了从 120、140、160 开始的数据。由于缺少 100 开始的那一段,它会反复发送:

1
2
3
4
ACK = 100
ACK = 100
ACK = 100
ACK = 100

这些就是 duplicate ACK。

6.2 为什么 3 个重复 ACK 触发快速重传?

如果发送方收到 3 个重复 ACK,通常意味着:

接收方收到了后续多个 segment,但中间某个 segment 缺失。

这时不必等 timeout,可以提前重传缺失 segment。

快速重传的价值是:

1
不用等超时,提前恢复可能丢失的数据。

❗ 本节核心结论:
重复 ACK 不是确认了更多数据,而是在反复提示“我还在等同一个缺口”。

7. TCP 流量控制 Flow Control

流量控制解决的问题是:

发送方不要发得太快,避免接收方 buffer 溢出。

注意,流量控制保护的是 接收方,不是网络。

7.1 为什么需要流量控制?

接收方收到 TCP segment 后,数据会进入接收缓冲区。应用程序再从 socket buffer 中读取数据。

如果:

1
TCP 放入 buffer 的速度 > 应用程序读取 buffer 的速度

接收缓冲区就可能被撑爆。

7.2 rwnd 的作用

接收方通过 TCP 首部中的 rwnd 字段告诉发送方:

1
我现在还有多少空闲接收缓冲区。

发送方要保证:

1
未确认的 in-flight 字节数 ≤ rwnd

这样可以避免发送方发送过多数据,导致接收方缓存溢出。

7.3 流量控制 vs 拥塞控制

对比项 流量控制 拥塞控制
保护对象 接收方 网络
主要问题 接收方应用读得慢,buffer 不够 路由器、链路、网络路径负载过高
典型信号 rwnd 丢包、超时、重复 ACK、拥塞窗口
控制目的 不淹没接收方 不压垮网络

❗ 本节核心结论:
流量控制管的是“接收方吃不吃得下”;拥塞控制管的是“网络扛不扛得住”。

8. TCP 连接管理

TCP 是面向连接的协议。传输数据前需要建立连接,结束后需要关闭连接。

但这个连接不是物理线路,而是两端主机维护的一组状态:

  • 初始序号;
  • 当前发送序号;
  • 当前确认号;
  • 接收窗口;
  • 发送窗口;
  • 定时器;
  • 连接状态。

9. 为什么两次握手不够?

两次握手正常情况下看似能工作:

1
2
Client → Server: req_conn(x)
Server → Client: acc_conn(x)

但问题出现在真实网络会有:

  • 延迟;
  • 重传;
  • 乱序;
  • 旧报文残留;
  • 双方无法直接看见对方状态。

两次握手的根本问题是:

Server 可能过早进入 ESTABLISHED 状态。

9.1 问题一:half-open connection

假设旧的连接请求 req_conn(x) 在网络中延迟很久后才到达服务器。

时间线如下:

  1. Client 曾经发送 req_conn(x)
  2. 连接后来已经结束;
  3. Client 已经不想建立这条连接;
  4. 某个旧的 req_conn(x) 现在才到达 Server;
  5. Server 误以为这是新的连接请求;
  6. Server 回复 acc_conn(x)
  7. Server 进入 ESTABLISHED;
  8. Client 实际上没有这条连接。

结果:

1
2
Server 认为连接建立了;
Client 并没有这个连接。

这就是 half-open connection,半连接

本质原因是:

两次握手中,Server 没有确认 Client 是否真的收到了自己的响应,也没有确认 Client 现在是否仍然愿意建立连接。

9.2 问题二:old duplicate data 被误认为新数据

更严重的是,旧数据也可能被误收。

假设旧连接中有:

1
2
req_conn(x)
data(x+1)

这条连接已经结束,但网络中残留了旧的 req_conn(x) 和旧的 data(x+1)

之后:

  1. 旧的 req_conn(x) 延迟到达 Server;
  2. Server 误以为是新连接请求;
  3. Server 进入连接状态;
  4. 旧的 data(x+1) 也延迟到达;
  5. Server 发现数据序号正好符合这个“假连接”;
  6. Server 把旧数据当成新数据接收。

结果就是:

1
旧连接的数据被误认为当前新连接的数据。

❗ 本节核心结论:
两次握手的问题不在于正常情况不能建立连接,而在于遇到旧报文、延迟、重传时,服务器可能误建连接、误收旧数据。

10. TCP 三次握手

三次握手的目标是:

让双方都确认对方活着,并且双方都确认对方选择的初始序号。

流程如下:

10.1 第一次握手:Client 发 SYN

1
Client → Server: SYN = 1, Seq = x

含义:

  • Client 想建立连接;
  • Client 选择初始序号 x
  • 后续 Client 发送的数据会从 x+1 附近开始。

为什么是 x+1

因为 SYN 本身会消耗一个序号。

10.2 第二次握手:Server 发 SYNACK

1
Server → Client: SYN = 1, Seq = y, ACK = x + 1

这一步有两层含义:

第一层:

1
ACK = x + 1

表示:

1
2
我收到了你的 SYN,确认你的初始序号 x;
我期待你下一个序号是 x+1。

第二层:

1
SYN = 1, Seq = y

表示:

1
2
我也同意建立连接;
我选择自己的初始序号 y。

所以第二次握手是 SYN 和 ACK 合在一起,通常叫 SYNACK

10.3 第三次握手:Client 确认 Server 的初始序号

1
Client → Server: ACK = y + 1

含义:

1
2
我收到了你的 SYN,确认你的初始序号 y;
我期待你下一个序号是 y+1。

这一步非常关键。

没有第三次握手,Server 不知道 Client 是否真的收到了自己的 Seq = y。也就是说,Server 不知道 Client 是否已经知道服务器端初始序号。

三次握手完成后,双方状态如下:

确认内容 是否完成
Server 知道 Client 活着
Client 知道 Server 活着
Server 确认 Client 的初始序号 x
Client 确认 Server 的初始序号 y

❗ 本节核心结论:
三次握手不是形式主义,而是为了让双方都确认对方的初始序号,从而避免半连接和旧数据误收。

11. 三次握手如何缓解两次握手的问题?

11.1 缓解 half-open connection

如果一个旧 SYN 延迟到达 Server,Server 可能回复 SYNACK。

但在三次握手中,Server 不会仅凭自己发出 SYNACK 就确认连接稳定建立。它还要等 Client 的第三次 ACK。

如果 Client 根本没有这条连接,就不会返回正确的第三次 ACK。

因此 Server 不会最终完成这个连接。

11.2 缓解 old duplicate data

三次握手还配合 变化的初始序号 使用。

新连接不会简单沿用旧连接的序号范围。这样旧数据即使后来到达,也很难刚好落入当前连接的合法接收窗口。

所以三次握手解决问题靠两点:

  1. 双方都确认对方的初始序号;
  2. 每次连接使用变化的初始序号,减少旧数据被误收的可能。

12. TCP 连接关闭

TCP 是全双工连接,所以两端可以分别关闭自己这一侧。

一方关闭发送方向时,会发送:

1
FIN = 1

对方收到 FIN 后回复 ACK。

之后对方也可以发送自己的 FIN,原发送方再 ACK。

可以理解为:

1
2
我不再发数据了,但我仍然可以接收你发来的数据;
你也不发了以后,再关闭另一半。

❗ 本节核心结论:
TCP 连接关闭是双向的。每一方都要分别关闭自己的发送方向,所以通常需要 FIN 和 ACK 的交换。

13. 重要对比表

13.1 SEQ vs ACK

对比项 SEQ ACK
中文 序号 确认号
表示谁的数据 本方发送的数据 对方发送的数据
含义 本 segment 首字节编号 期待收到的下一个字节编号
是否按字节计数
常见误解 以为是第几个 segment 以为是最后收到的字节编号

13.2 超时重传 vs 快速重传

对比项 超时重传 快速重传
触发条件 定时器超时 收到 3 个重复 ACK
反应速度 较慢 较快
依据 时间 接收方重复 ACK
说明什么 长时间没有确认 后续段到了,但中间有缺口
重传对象 最早未确认段 推测丢失的段

13.3 流量控制 vs 可靠传输

对比项 可靠传输 流量控制
解决什么 丢包、乱序、重复 接收方 buffer 溢出
核心机制 SEQ、ACK、timer、retransmission rwnd
关注对象 数据是否正确到达 接收方是否接得住
典型问题 ACK 丢失、segment 丢失 应用层读取太慢

14. 易混点整理

14.1 TCP 的 ACK 不是“我收到了这个编号”

ACK = n 表示:

1
我期待下一个收到编号为 n 的字节。

它实际确认的是 n 之前的连续字节。

14.2 TCP 的序号不是报文段编号

TCP 按字节编号,而不是按 segment 编号。

14.3 累计确认不是选择确认

累计 ACK 只能说明某个位置之前的连续字节都收到了。
它不能直接表达“后面的某几个乱序 segment 我也收到了”。

14.4 快速重传不是 timeout

快速重传由 3 个重复 ACK 触发,不是由定时器超时触发。

14.5 流量控制不是拥塞控制

流量控制保护接收方。
拥塞控制保护网络。

14.6 三次握手不是多发一次而已

三次握手的关键是:

1
2
Server 确认 Client 的初始序号;
Client 确认 Server 的初始序号。

这让双方连接状态同步,降低半连接和旧数据误收风险。


15. 自测题:暂不附答案

  1. TCP 为什么说是“面向连接”的?这个连接是物理连接吗?

  2. TCP 为什么说提供的是“字节流”服务,而不是“报文”服务?

  3. TCP 的 sequence number 表示什么?为什么不是 segment 编号?

  4. ACK = 100 的准确含义是什么?

  5. 为什么说 TCP 使用的是 cumulative ACK?

  6. SampleRTT 是怎么测量的?为什么重传过的 segment 通常不用于 SampleRTT 测量?

  7. EstimatedRTT 为什么不用单次 SampleRTT 直接代替?

  8. TimeoutInterval 为什么要加上 4 * DevRTT

  9. 超时时间设置过短和过长分别有什么问题?

  10. 简化版 TCP 发送方主要处理哪三类事件?

  11. TCP 超时后重传的是所有未确认段,还是最早未确认段?

  12. 什么是重复 ACK?为什么重复 ACK 可以暗示某个 segment 丢失?

  13. 快速重传为什么通常等待 3 个重复 ACK,而不是 1 个?

  14. rwnd 的作用是什么?发送方如何根据 rwnd 限制发送?

  15. 流量控制和拥塞控制的区别是什么?

  16. 两次握手为什么可能造成 half-open connection?

  17. 旧的 duplicate data 为什么可能在两次握手机制下被错误接收?

  18. 三次握手中 SYN、SYNACK、ACK 分别完成了什么确认?

  19. TCP 关闭连接时,为什么双方要分别关闭自己这一侧连接?

  20. 为什么说 TCP 同时借鉴了 GBN 和 SR 的一些思想?


最终总结

Chapter 3-4 的核心是 TCP。TCP 在 IP 不可靠服务之上,通过一整套端系统机制,向应用层提供可靠、按序、面向连接的字节流服务。

本节最重要的几个判断是:

  • TCP 是 字节流协议,不是报文流协议;
  • TCP 的 sequence number 是 字节编号,不是 segment 编号;
  • TCP 的 ACK number 表示 下一个期待的字节编号
  • TCP 使用 累计确认
  • RTT 估计和 TimeoutInterval 决定重传时机;
  • 快速重传通过重复 ACK 提前发现缺口;
  • rwnd 用于流量控制,防止接收方 buffer 溢出;
  • 三次握手用于确认双方初始序号,避免半连接和旧数据误收;
  • TCP 连接关闭是双向的,两端分别关闭自己的发送方向。

❗ 最终核心结论:
TCP 的本质不是“可靠地发送一个个包”,而是在不可靠 IP 网络之上,为应用层构造一条可靠、按序、全双工、受控速率的字节流通道。