高级 #network#tcp#reliable
TCP 三次握手与可靠传输
TCP(Transmission Control Protocol)是互联网最核心的传输协议——通过三次握手建立连接、序列号保证顺序、确认和重传保证可靠,让不可靠的 IP 网络变成可靠的通信通道
把不可靠的网络变可靠
IP 层是”尽力而为”的——包可能丢失、乱序、重复。TCP 在 IP 之上增加了可靠性:让乱序的数据重新排序、让丢失的包重传、让重复的包去重。
🏫 类比:寄挂号信 vs 平信 UDP(平信):写了地址就寄出去——丢了不负责。 TCP(挂号信):寄出前确认你能收、每封信有编号(序列号)、收件人要签收确认(ACK)、没收到就重寄。
TCP 包头
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
┌───────────────┬───────────────────────────────────────────────┐
│ 源端口 │ 目标端口 │
├───────────────┼───────────────────────────────────────────────┤
│ 序列号(Sequence Number) │
├───────────────────────────────────────────────────────────────┤
│ 确认号(Acknowledgment Number) │
├───────┬───────┬───────────────────────────────────────────────┤
│ 偏移 │ 保留 │U│A│P│R│S│F│ 窗口大小(Window Size) │
├───────┴───────┴───────────────────────────────────────────────┤
│ 校验和 │ 紧急指针 │
├───────────────────────────────────────────────────────────────┤
│ 选项(可选) │
└───────────────────────────────────────────────────────────────┘
三次握手(Three-Way Handshake)
TCP 建立连接需要三次消息交换:
客户端 服务器
│ │
│ 1. SYN (seq=x) │
│ ──────────────────────────→ │
│ │
│ 2. SYN+ACK (seq=y, ack=x+1) │
│ ←────────────────────────── │
│ │
│ 3. ACK (seq=x+1, ack=y+1) │
│ ──────────────────────────→ │
│ │
│ 连接建立完成 │
│ 开始传输数据 │
# 用 tcpdump 观察三次握手
$ tcpdump -nn -i eth0 host 192.168.1.1 and port 80
14:23:01.123 IP 192.168.1.1.54321 > 203.0.113.1.80: S 1000:1000(0) win 65535
14:23:01.124 IP 203.0.113.1.80 > 192.168.1.1.54321: S 2000:2000(0) ack 1001 win 65535
14:23:01.124 IP 192.168.1.1.54321 > 203.0.113.1.80: . ack 2001 win 65535
💡 三次握手的核心目的:客户端确认自己→服务器通路和服务器→客户端通路都正常。同时双方交换初始序列号。
可靠传输机制
序列号
每个字节的数据都有一个序列号——接收方用序列号把数据排回正确的顺序。
发送方发:
[seq=1, 100字节] → 确认(ack=101)
[seq=101, 100字节] → 确认(ack=201)
[seq=201, 100字节] → 丢失!→ 超时重传
[seq=201, 100字节] → 重传 → 确认(ack=301)
确认与重传
发送方发完数据后启动定时器——如果在超时前收到 ACK,说明数据到达;如果超时未收到 ACK → 重传。
# TCP 发送方简化逻辑
def tcp_send(data):
seq = next_seq()
send_packet(seq, data)
start_timer()
while not acknowledged(seq):
if timer_expired():
# 超时——重传
# 指数退避(下次超时翻倍)
timeout *= 2
send_packet(seq, data)
restart_timer()
快速重传
如果接收方收到乱序的包——立即重复确认(DupACK)。发送方收到 3 次重复确认 → 立即重传(不等超时)。
发送方 接收方
│ │
│ [seq=1] →│ 正常收到,ack=2
│ [seq=2] │ 丢了!
│ [seq=3] →│ 乱序!ack=2(DupACK #1)
│ [seq=4] →│ 乱序!ack=2(DupACK #2)
│ [seq=5] →│ 乱序!ack=2(DupACK #3)
│ │
│← 3 次 DupACK │
│ [seq=2] 重传 │
四次挥手(连接关闭)
客户端 服务器
│ │
│ 1. FIN │
│ ──────────────────────────→ │
│ │ ← 服务器可能还在发数据
│ 2. ACK │
│ ←────────────────────────── │
│ │
│ 3. FIN │(服务器发完数据后)
│ ←────────────────────────── │
│ │
│ 4. ACK │
│ ──────────────────────────→ │
│ │
│ 连接关闭 │
小结
| 概念 | 要点 |
|---|---|
| 三次握手 | SYN → SYN+ACK → ACK 建立连接 |
| 序列号 | 为每个字节编号,保证有序性 |
| 确认+重传 | 超时或三次 DupACK 触发重传 |
| 四次挥手 | FIN → ACK → FIN → ACK 关闭连接 |
| 有状态 | 两端都需要维护连接状态 |
为什么先学这个? TCP 的可靠传输机制是互联网的基石。下一节看看TCP 流量控制与拥塞控制——TCP 如何避免发送太快把网络”塞爆”。