1. 简介
如果说 RFC 793 构建了 TCP 的骨架,让它能在 80 年代的低速网络上可靠运行;那么 RFC 1323 (1992年发布,后被 RFC 7323 更新) 就是给 TCP 装上了“涡轮增压”,让它能跑满现代的光纤和卫星链路。
在 RFC 793 的时代,网络带宽只有几 Kbps,延迟几十毫秒。但在现代 长肥网络 (Long Fat Networks, LFNs) ——即高带宽 × 高延迟的网络环境下,原始 TCP 遇到了两个致命瓶颈:
- 窗口太小:16 位窗口最大仅 64KB,在高延迟下无法填满管道,带宽利用率极低。
- 序列号回绕太快:在 Gbps 级带宽下,32 位序列号(4GB)几秒就会循环一圈,导致旧报文混淆(PAWS 问题)。
RFC 1323 引入了三个关键扩展,彻底解决了这些问题。
1.1 窗口扩大选项 (Window Scale Option) —— 突破 64KB 枷锁
1.1.1 痛点:64KB 的天花板
TCP 头部中的 Window 字段只有 16 位。
Max Window =
场景推演:
假设你有一条 100 Mbps 的专线,往返延迟 (RTT) 为 100 ms (典型的跨国链路)。
- 带宽延迟积 (BDP): 。
- 问题:管道容量是 1.25 MB,但 TCP 窗口只允许发送 64 KB。
- 后果:发送方每发 64 KB 数据,就必须停下来等待 ACK。此时链路利用率仅为: , 95% 的带宽被白白浪费了!
1.1.2 解决方案:左移魔法
RFC 1323 定义了一个 Window Scale 选项(在 TCP Options 中),包含一个 移位计数 (Shift Count, S) 。
- 原理:实际窗口大小 =
通告窗口值≪ S (即 )。 - 范围: S 取值 0~14。
- 最大能力: 。足以应对未来的超高速网络。
1.1.3 协商机制 (关键点)
-
时机:只能在 三次握手的 SYN 包 (第一次和第二次) 中携带。
-
单向性:客户端和服务端各自声明自己的接收窗口扩大因子(因为收发是独立的)。
- Client SYN:
WS=7(表示我能接收 2727 倍的窗口) - Server SYN+ACK:
WS=5(表示我能接收 2525 倍的窗口)
- Client SYN:
-
不可逆:如果握手时没带这个选项,或者中间设备把它过滤了,连接建立后永远无法开启窗口扩大,只能憋屈地用 64KB。
1.1.4 Window Scale ≠ 可以无限发送
Window Scale 只是扩大“接收端通告窗口(rwnd)的表示能力” ,并不等价于发送端可以无限制发送数据。
发送端真正可发送的数据量始终受以下关系约束:
Effective Send Window = min(rwnd, cwnd)
- rwnd:接收端通告窗口(可能经过 Window Scale 扩大)
- cwnd:拥塞窗口,由拥塞控制算法动态决定
结论:
- Window Scale 解决的是:接收端敢不敢收
- 拥塞控制解决的是:网络允不允许发
两者缺一不可。
1.1.5 实战排查:为什么我的大文件传输这么慢?
-
现象:带宽很大,但传输速度卡在几十 MB/s 上不去,且 Wireshark 看到大量 "Zero Window" 或发送方频繁停顿。
-
检查步骤:
-
抓包看握手:检查 SYN 包中是否有
Window Scale选项。Options: (mss 1460, nop, ws 7, nop, nop, TS val ...) -
检查内核参数:
sysctl net.ipv4.tcp_window_scaling # 必须为 1 -
防火墙背锅:有些老旧的防火墙或 NAT 设备会错误地丢弃或篡改带有未知 Options 的包,导致握手降级。这是生产环境常见的隐性性能杀手。
-
1.2 时间戳选项 (Timestamps Option) —— 精确测距与防老
RFC 1323 定义了另一个关键选项:Timestamps。它在每个 TCP 报文中携带两个 32 位值:
- TSval (Timestamp Value) :发送方的当前时钟计数。
- TSecr (Timestamp Echo Reply) :对最近收到的报文 TSval 的回显。
它解决了两个核心问题:
1.2.1 问题一:PAWS (Protection Against Wrapped Sequence numbers)
我们在之前讨论过,高速网络下序列号回绕极快。
-
机制:接收方维护一个
recent_ts变量。- 如果收到报文的
TSval<recent_ts:直接丢弃(判定为旧连接的幽灵报文)。 - 如果
TSval>=recent_ts:更新recent_ts并正常处理。
- 如果收到报文的
-
价值:即使序列号回绕到了 0,只要时间戳是递增的,就能精准区分新旧数据。这是高速网络下 TCP 可靠性的最后一道防线。
1.2.2 问题二:精确的 RTT 测量
RFC 793 的 RTT 测量在重传时有歧义(Karn 算法虽然缓解了,但不够实时)。
-
机制:
- 发送方记录发送时间 T1 (放入 TSval)。
- 接收方回显 T1 (放入 TSecr)。
- 发送方收到回显时记录 T2 。
- RTT = T2−T1 。
-
价值:即使是在重传段上,也能精确计算 RTT。这对于现代拥塞控制算法(如 BBR)至关重要,因为 BBR 极度依赖精确的 RTT 来估算带宽。
1.2.3 实战排查
-
现象:连接偶尔莫名重置 (RST),尤其是在经过复杂 NAT 或负载均衡集群时。
-
原因:某些网络设备会错误地修改 TCP 时间戳,或者后端服务器集群时间不同步,导致 PAWS 机制误判合法报文为“旧报文”而丢弃。
-
验证:
sysctl net.ipv4.tcp_timestamps # 默认为 1 (开启)。如果在特定网络环境下有问题,可尝试临时关闭测试 (设为 0),但会牺牲性能。
1.3 综合图解:现代 TCP 的握手升级
结合 RFC 793 和 1323,现代 TCP 的三次握手实际上是这样的:
| 步骤 | 方向 | 标志位 | 关键 Options (RFC 1323 贡献) | 含义 |
|---|---|---|---|---|
| 1 | C -> S | SYN | MSS=1460, WS=7, TSval=100 | 客户端:“我最大段1460,窗口扩大7倍,当前时间100。” |
| 2 | S -> C | SYN+ACK | MSS=1460, WS=5, TSval=200, TSecr=100 | 服务端:“收到。我窗口扩大5倍,当前时间200,回显你的时间100。” |
| 3 | C -> S | ACK | WS=7 (隐含), TSval=300, TSecr=200 | 客户端:“握手完成。回显你的时间200。开始传输!” |
一旦握手成功,后续所有数据包(包括纯 ACK 包)都会携带
TSval和TSecr,用于持续的 RTT 测量和 PAWS 保护。
1.4 总结:从“能用”到“好用”
RFC 1323 的引入,标志着 TCP 从“保证连通”进化为“保证性能”。
| 特性 | RFC 793 (原始) | RFC 1323 (扩展) | 现代意义 |
|---|---|---|---|
| 最大窗口 | 64 KB | 1 GB | 跑满千兆/万兆光纤的基础 |
| 序列号保护 | 无 (易受回绕攻击) | PAWS (基于时间戳) | 高速网络下的数据完整性保障 |
| RTT 测量 | 模糊 (重传时不准) | 精确 (每个包都可测) | BBR 等现代拥塞控制算法的基石 |
给开发者的建议:
- 默认开启:现代 Linux 内核默认开启
tcp_window_scaling和tcp_timestamps,千万不要随意关闭,除非遇到极特殊的兼容性故障。 - 关注中间设备:如果你的应用部署在复杂的云网络或跨国链路中,发现性能不达标,优先检查防火墙/负载均衡是否剥离了 TCP Options。
- 理解 BBR:如果你在使用 Google 的 BBR 拥塞控制算法,请知道它完全依赖于 RFC 1323 的时间戳机制。没有 1323,就没有 BBR。