TCP 与上层/下层交互
TCP 与 IP 层的协作
TCP 依赖 IP 层提供的主机到主机交付,但 IP 是不可靠的。TCP 通过以下方式与 IP 协作:
伪首部校验
TCP 校验和覆盖伪首部(包含源 IP、目的 IP、协议类型、TCP 长度),确保 IP 层路由错误能被检测:
分片与 PMTUD
IP 层分片对 TCP 透明,但 TCP 需要配合 PMTUD:
- IPv4:DF=1 时路由器不能分片,丢包后 ICMP 通知 TCP 降 MSS
- IPv6:中间路由器绝对不分片,源端必须按路径 MTU 发包
TCP 与 TLS/SSL
HTTPS = HTTP over TLS over TCP:
TLS 握手与 TCP 握手的叠加
TLS 1.3 优化:
- 握手压缩至 1-RTT(甚至 0-RTT 会话恢复)
- 与 TCP 的 TFO(Fast Open)协同,进一步减少延迟
TCP 与 HTTP 的演进
| HTTP 版本 | 传输层 | 连接模型 | 关键特性 |
|---|---|---|---|
| HTTP/1.0 | TCP | 短连接 | 每个请求新建 TCP 连接 |
| HTTP/1.1 | TCP | 持久连接 | Keep-Alive 复用连接 |
| HTTP/2 | TCP | 单连接多路复用 | 二进制分帧、流、头部压缩 |
| HTTP/3 | QUIC/UDP | 连接迁移 | 0-RTT、内置加密、无队头阻塞 |
HTTP/2 的 TCP 队头阻塞
HTTP/2 在单条 TCP 连接上多路复用多个流,但 TCP 是按序交付的。如果某个流的数据包丢失,TCP 必须等待重传,导致其他流的数据也被阻塞——这就是 TCP 队头阻塞(Head-of-Line Blocking)。
QUIC:TCP 的演进替代
QUIC(RFC 9000)基于 UDP 重构了类似 TCP 的可靠性,同时解决 TCP 的痛点:
| 特性 | TCP | QUIC |
|---|---|---|
| 传输层 | TCP | UDP |
| 连接标识 | 四元组 | Connection ID |
| 连接迁移 | 困难(IP/端口变则断) | 容易(Connection ID 不变) |
| 队头阻塞 | 存在(TCP 按序) | 消除(流独立传输) |
| 加密 | 上层 TLS | 内置 TLS 1.3 |
| 握手延迟 | 1-RTT(+ TLS 1-2 RTT) | 0-RTT 或 1-RTT |
| 拥塞控制 | 内核实现 | 用户空间实现 |
QUIC 的连接迁移:
- 手机从 Wi-Fi 切换到 4G,IP 地址改变
- TCP 连接因四元组变化而中断
- QUIC 通过 Connection ID 标识连接,IP 变化不影响
本篇小结
- TCP 伪首部包含 IP 地址,检测路由错误
- TCP 配合 PMTUD,DF=1 探测路径 MTU
- TLS 在 TCP 之上提供加密,TLS 1.3 1-RTT 握手
- HTTP 演进:短连接 → Keep-Alive → HTTP/2 多路复用 → HTTP/3 QUIC
- HTTP/2 的 TCP 队头阻塞:单连接丢包阻塞所有流
- QUIC 基于 UDP,解决队头阻塞、连接迁移、内置 TLS
动手实践
查看浏览器支持的 HTTP 版本:
- Chrome DevTools → Network → Protocol 列(h2=HTTP/2, h3=HTTP/3)
用 curl 测试 HTTP/3:
curl --http3 -I https://cloudflare.comWireshark 抓包对比 HTTP/1.1 vs HTTP/2:
- HTTP/2 过滤
http2 - 观察多路复用的 Stream ID
- HTTP/2 过滤
思考:为什么 QUIC 选择基于 UDP 而不是改造 TCP?如果直接修改 TCP 内核实现,会遇到什么部署难题?