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 = <math xmlns="http://www.w3.org/1998/Math/MathML"> 2 16 − 1 = 65 , 535 B y t e s ≈ 64 K B {2}^{16}−1 = 65,535 Bytes ≈ 64 KB </math>216−1=65,535 Bytes≈64 KB
场景推演 :
假设你有一条 100 Mbps 的专线,往返延迟 (RTT) 为 100 ms (典型的跨国链路)。
- 带宽延迟积 (BDP) : <math xmlns="http://www.w3.org/1998/Math/MathML"> 100 M b p s × 0.1 s = 10 M b i t s = 1.25 M B 100 Mbps×0.1 s=10 Mbits=1.25 MB </math>100 Mbps×0.1 s=10 Mbits=1.25 MB 。
- 问题 :管道容量是 1.25 MB ,但 TCP 窗口只允许发送 64 KB。
- 后果 :发送方每发 64 KB 数据,就必须停下来等待 ACK。此时链路利用率仅为: <math xmlns="http://www.w3.org/1998/Math/MathML"> 64 K B / 1.25 M B ≈ 5 % 64 KB / 1.25 MB ≈ 5\% </math>64 KB/1.25 MB≈5% , 95% 的带宽被白白浪费了!
1.1.2 解决方案:左移魔法
RFC 1323 定义了一个 Window Scale 选项(在 TCP Options 中),包含一个 移位计数 (Shift Count, S) 。
- 原理 :实际窗口大小 =
通告窗口值≪ S (即 <math xmlns="http://www.w3.org/1998/Math/MathML"> × 2 S ×2^{S} </math>×2S )。 - 范围: S 取值 0~14。
- 最大能力 : <math xmlns="http://www.w3.org/1998/Math/MathML"> 65535 × 2 14 ≈ 1 G B 65535×2^{14} ≈ 1 GB </math>65535×214≈1 GB 。足以应对未来的超高速网络。
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)的表示能力" ,并不等价于发送端可以无限制发送数据。
发送端真正可发送的数据量始终受以下关系约束:
ini
Effective Send Window = min(rwnd, cwnd)
- rwnd:接收端通告窗口(可能经过 Window Scale 扩大)
- cwnd:拥塞窗口,由拥塞控制算法动态决定
结论:
- Window Scale 解决的是:接收端敢不敢收
- 拥塞控制解决的是:网络允不允许发
两者缺一不可。
1.1.5 实战排查:为什么我的大文件传输这么慢?
-
现象:带宽很大,但传输速度卡在几十 MB/s 上不去,且 Wireshark 看到大量 "Zero Window" 或发送方频繁停顿。
-
检查步骤:
-
抓包看握手 :检查 SYN 包中是否有
Window Scale选项。yamlOptions: (mss 1460, nop, ws 7, nop, nop, TS val ...) -
检查内核参数:
bashsysctl 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 机制误判合法报文为"旧报文"而丢弃。
-
验证:
scsssysctl 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。