3. TCP 序列号与确认机制:序列号(SEQ)、确认号(ACK)、滑动窗口原理
TCP 的可靠性核心在于其精密的序列号与确认机制。序列号(SEQ)用于标识字节流中的每一个字节,确认号(ACK)则告知发送方已成功接收的数据位置。滑动窗口则在此基础上实现了流量控制与高效传输。理解这三者的协同关系,是排查网络丢包与重传问题的关键。
3.1 序列号(SEQ)与确认号(ACK)
TCP 将应用层数据视为连续的字节流。每个字节在流中都有一个唯一的序号。序列号(SEQ)字段表示当前报文段中第一个字节的序号。确认号(ACK)字段表示期望接收的下一个字节的序号,同时也隐含地确认了该序号之前的所有字节均已成功接收。
核心规则:ACK 号 = 已成功接收的最后一个字节的序号 + 1。例如,收到 SEQ=1001,长度 100 字节的数据,则回复 ACK=1101。
排查要点:在抓包分析中,若发现大量重复的 ACK 号(如连续 3 个相同的 ACK),通常意味着对端未收到期望的报文段,这是触发快速重传的典型信号。
3.1.1 三次握手阶段的 SEQ/ACK 交换
| 步骤 | 方向 | 报文内容 | 说明 |
|---|---|---|---|
| 1 | 客户端 → 服务器 | SYN, SEQ=x | 客户端初始化序列号 x,请求建立连接 |
| 2 | 服务器 → 客户端 | SYN+ACK, SEQ=y, ACK=x+1 | 服务器确认客户端 SYN,并发送自己的 SYN |
| 3 | 客户端 → 服务器 | ACK, SEQ=x+1, ACK=y+1 | 客户端确认服务器 SYN,连接建立完成 |
3.2 滑动窗口原理
滑动窗口是 TCP 实现流量控制和可靠传输的核心机制。它允许发送方在未收到确认的情况下,连续发送多个报文段,从而充分利用网络带宽。窗口大小由接收方的接收能力(接收缓冲区剩余空间)决定,并通过 TCP 头部的 Window 字段通告给发送方。
3.2.1 发送方窗口结构
发送方维护的窗口被划分为四个区域:
- 已发送并已确认:最左侧,已安全送达。
- 已发送但未确认:等待 ACK 的报文段。
- 允许发送但未发送:窗口内剩余可用空间。
- 不允许发送:超出窗口范围,必须等待窗口滑动。
常见问题:当接收方处理速度慢于发送方时,接收方会通告较小的窗口(甚至零窗口)。若发送方持续发送,将导致数据在接收缓冲区溢出而被丢弃,进而触发重传。排查时需关注抓包中的 Window 字段变化。
3.3 SEQ/ACK 与滑动窗口的协同工作
在实际传输中,SEQ、ACK 和滑动窗口三者紧密配合。发送方根据窗口大小连续发送数据,接收方收到后回复 ACK 并更新窗口大小。若发生丢包,接收方会持续发送重复 ACK(DupACK),发送方据此判断丢包并触发重传。
3.3.1 正常传输与丢包场景对比
| 场景 | 发送方行为 | 接收方行为 | 抓包特征 |
|---|---|---|---|
| 正常传输 | 按窗口大小连续发送,收到 ACK 后滑动窗口 | 按序接收,回复累积 ACK | SEQ 连续递增,ACK 稳步增长 |
| 单包丢失 | 收到 3 个重复 ACK 后快速重传丢失报文 | 缓存后续报文,持续发送丢失报文的 ACK | 连续 3 个以上相同 ACK 号,随后出现重传 SEQ |
| 窗口满 | 停止发送,等待 ACK 释放窗口 | 通告零窗口或小窗口 | Window 字段逐渐减小至 0 |
3.4 排查实践:从抓包中识别 SEQ/ACK 异常
在 Wireshark 或 tcpdump 抓包中,以下现象是排查的重点:
- ACK 号停滞:长时间未更新,表明接收方未收到新数据。
- 重复 ACK:连续出现相同 ACK 号,是丢包的直接证据。
- 窗口大小骤降:接收方处理能力不足,可能导致零窗口探测。
- SEQ 跳跃:出现非连续的 SEQ 号,通常伴随重传。
排查命令示例:使用 tcpdump 抓取特定端口的 TCP 流量,并过滤 SEQ/ACK 异常。
# 抓取 80 端口流量,显示 SEQ 和 ACK
tcpdump -i eth0 -nn -S port 80
# 过滤重复 ACK(假设目标 IP 为 10.0.0.2)
tcpdump -i eth0 -nn "tcp[13] & 24 == 16" and host 10.0.0.2
专家建议:在 Wireshark 中启用“TCP Analysis Flags”列,可以自动标记出重传、重复 ACK、窗口更新等事件,大幅提升排查效率。