第4章:传输层(Transport Layer)
一、导读
1.1 本章学习目标
第4章讲解传输层——提供端到端的通信服务。TCP 和 UDP 是互联网最重要的两个传输层协议,本章深入分析它们的机制和设计权衡。
本章核心学习目标:
- 掌握 TCP 的可靠传输机制:序号、确认、重传、滑动窗口
- 理解 TCP 的拥塞控制:慢启动、拥塞避免、快重传、快恢复
- 掌握 TCP 的连接管理:三次握手、四次挥手
- 理解 UDP 的适用场景:为什么有些应用选择不可靠的传输?
- 掌握流量控制和拥塞控制的区别
1.2 为什么本章如此重要
TCP 是互联网上最广泛使用的协议之一,理解其内部机制对于网络编程、性能调优和问题排查至关重要。
1.3 核心问题引导
TCP 为什么需要三次握手而不是两次?
拥塞控制的慢启动为什么是指数增长?
TCP 的公平性是如何实现的?
二、核心概念详解
2.1 TCP 可靠传输
TCP 的可靠传输机制:
1. 序号: 每个字节都有序号,按序交付
2. 确认: 接收方确认已收到的最高序号
3. 超时重传: 超时未确认则重传
4. 滑动窗口: 允许发送多个未确认的分组
累积确认:
ACK = 36 → 序号 ≤ 35 的所有字节已收到
下一个期望的字节序号 = 36
选择性确认 (SACK):
允许接收方告知哪些块已收到,哪些缺失
减少不必要的重传2.2 TCP 拥塞控制
TCP Reno 拥塞控制:
慢启动 (Slow Start):
- cwnd 从 1 MSS 开始
- 每收到一个 ACK,cwnd += 1
- 效果: 每 RTT cwnd 翻倍(指数增长)
- 直到 cwnd ≥ ssthresh 或丢包
拥塞避免 (Congestion Avoidance):
- cwnd ≥ ssthresh 后进入
- 每 RTT cwnd += 1(线性增长)
- 直到丢包
快重传 (Fast Retransmit):
- 收到 3 个重复 ACK → 立即重传
- 不等待超时
快恢复 (Fast Recovery):
- 快重传后: ssthresh = cwnd/2, cwnd = ssthresh + 3
- 进入拥塞避免阶段
cwnd 变化示意:
cwnd
↑ /\ /\
| / \ / \
| / \ / \
| / \ / \
|/ \/ \___
+------------------------→ time
|← 慢启动 →|← 拥塞避免 →|2.3 TCP 连接管理
三次握手:
Client Server
|---SYN (seq=x)--->|
|<--SYN+ACK (seq=y, ack=x+1)--|
|---ACK (ack=y+1)->|
| |
| 连接建立 |
为什么需要三次?
- 两次: 无法确认 Client 收到了 Server 的 SYN+ACK
→ 可能导致 Server 以为连接已建立,但 Client 不知道
- 三次: 双方都确认了对方的初始序号
四次挥手:
Client Server
|---FIN (seq=u)--->| Client 发送 FIN,进入 FIN_WAIT_1
|<--ACK (ack=u+1)--| Server 确认,Client 进入 FIN_WAIT_2
| | Server 继续发送剩余数据(半关闭)
|<--FIN (seq=w)----| Server 发送 FIN,进入 LAST_ACK
|---ACK (ack=w+1)->| Client 确认,进入 TIME_WAIT
| | Server 收到 ACK,进入 CLOSED
| (等待 2MSL) | Client 等待后进入 CLOSED
为什么需要 TIME_WAIT (2MSL)?
1. 确保最后的 ACK 到达 Server(如果丢失,Server 会重发 FIN)
2. 等待网络中该连接的残留分组消失(防止新连接收到旧数据)
MSL = Maximum Segment Lifetime = 2 分钟(RFC 793)三、实战案例
3.1 案例一:TCP 拥塞控制模拟
python
class TCPCongestionControl:
def __init__(self, mss=1460):
self.cwnd = 1 * mss
self.ssthresh = 65535
self.mss = mss
self.dup_acks = 0
def on_ack(self, ack):
"""收到 ACK"""
self.dup_acks = 0
if self.cwnd < self.ssthresh:
# 慢启动: 指数增长
self.cwnd += self.mss
else:
# 拥塞避免: 线性增长
self.cwnd += self.mss * self.mss // self.cwnd
def on_dup_ack(self):
"""收到重复 ACK"""
self.dup_acks += 1
if self.dup_acks == 3:
# 快重传
self.ssthresh = max(self.cwnd // 2, 2 * self.mss)
self.cwnd = self.ssthresh + 3 * self.mss
self.dup_acks = 0
def on_timeout(self):
"""超时"""
self.ssthresh = max(self.cwnd // 2, 2 * self.mss)
self.cwnd = self.mss
def get_cwnd_mss(self):
return self.cwnd // self.mss
# 模拟
tcp = TCPCongestionControl()
print("慢启动阶段:")
for i in range(6):
print(f" RTT {i}: cwnd = {tcp.get_cwnd_mss()} MSS")
tcp.on_ack(0)
print("\n丢包 (超时):")
tcp.on_timeout()
print(f" ssthresh = {tcp.ssthresh // tcp.mss}, cwnd = {tcp.get_cwnd_mss()}")
print("\n拥塞避免阶段:")
for i in range(5):
tcp.on_ack(0)
print(f" RTT: cwnd = {tcp.get_cwnd_mss()} MSS")四、本章小结
TCP 通过序号、确认、重传和滑动窗口实现可靠传输
拥塞控制通过调节发送速率避免网络过载,慢启动+拥塞避免实现加性增乘性减
三次握手确保双方同步初始序号,四次挥手支持半关闭状态
五、思考与练习
思考题
为什么 TCP 的慢启动是指数增长而不是线性增长?
在高 BDP 网络中,TCP Reno 的性能为什么很差?
编程练习
实现 TCP 滑动窗口协议,支持选择性确认(SACK)。
模拟 TCP 拥塞控制的 cwnd 变化,绘制曲线图。