Appearance
TCP、UDP 与 QUIC
TCP 与 UDP 的区别
| 维度 | TCP | UDP |
|---|---|---|
| 连接 | 面向连接,通信前建立状态 | 无连接,直接发送数据报 |
| 可靠性 | 序号、确认、重传、校验保证可靠、有序字节流 | 尽力而为;不保证送达、顺序、去重或重传 |
| 边界 | 面向字节流,应用需要自行定义消息边界 | 保留数据报边界 |
| 控制 | 具备流量控制和拥塞控制 | 协议本身没有;应用可自行实现 |
| 首部 | 至少 20 字节,信息更丰富 | 固定 8 字节 |
| 场景 | Web、数据库、文件传输、远程登录 | DNS、实时音视频、游戏、QUIC |
UDP 的“快”来自协议开销和等待更少,不代表它没有拥塞问题或总是更低延迟。实时系统常在应用层接受部分丢包,或按业务需要添加可靠机制。
TCP 如何保证可靠性
- 序列号与累计确认(ACK):接收端确认“下一个期望的字节序号”,发送端据此判断已确认数据。
- 校验和:发现报文段在传输中损坏时丢弃,依赖重传恢复。
- 超时重传(RTO):未在估计超时时间内收到确认时重传,并基于 RTT 动态估计 RTO。
- 快速重传:收到多个重复 ACK(经典阈值为 3 个)通常推断有报文丢失,无需等待 RTO 即重传。
- 滑动窗口:允许连续发送多个未确认字节;乱序段可缓存、重复段可去重,从而实现有序交付。
- 流量控制与拥塞控制:分别保护接收方和网络。
流量控制:接收窗口
接收方在 TCP 首部的窗口字段通告可接收空间 rwnd。发送方的在途未确认数据不能超过接收窗口,避免接收缓冲区被压垮。窗口为 0 时发送方暂停普通发送,并通过窗口探测避免“窗口更新丢失”而永久等待。
拥塞控制:拥塞窗口
拥塞控制的目标是保护网络,与接收方处理能力无关。有效发送窗口约为:
text
min(接收窗口 rwnd, 拥塞窗口 cwnd)经典 Reno 的面试表述:
- 慢启动:
cwnd从较小值开始,收到 ACK 后快速增长,近似每 RTT 翻倍; - 拥塞避免:达到
ssthresh后线性增长,近似每 RTT 增加一个 MSS; - 快速重传:多个重复 ACK 后立即重传疑似丢失报文;
- 快速恢复:认为仍有部分数据在网络中,不完全退回初始慢启动;阈值通常按丢失前窗口的一部分设置。
实际操作系统可能使用 CUBIC、BBR 等算法,具体行为不完全等同于 Reno。
TCP 三次握手
text
客户端 服务端
CLOSED LISTEN
── SYN, seq=x ──────────────────────────> SYN_RCVD
SYN_SENT
<────────────── SYN, seq=y; ACK, ack=x+1 ─
── ACK, ack=y+1 ────────────────────────> ESTABLISHED
ESTABLISHED三次握手使双方都确认初始序号,并建立双向收发能力:
- 客户端 SYN 表明客户端希望建立连接且其发送路径能到达服务器;
- 服务端 SYN+ACK 确认收到客户端 SYN,同时发出自己的 SYN;
- 客户端 ACK 确认收到了服务端 SYN,服务端收到该 ACK 后也确认客户端能收到自己的报文。
为什么不是两次? 服务端仅回复 SYN+ACK 后,无法确认客户端是否收到自己的 SYN,也更难处理网络中延迟、重复的旧连接请求;第三次 ACK 让服务端再进入已建立状态。
TCP 四次挥手与 TIME_WAIT
TCP 是全双工字节流,一方发送 FIN 仅表示“我不再发送”,但仍可接收数据:
text
主动关闭方 被动关闭方
FIN, seq=x ──────────────────────────────> CLOSE_WAIT
<──────────────────── ACK, ack=x+1
FIN_WAIT_2
<──────────────────── FIN, seq=y
ACK, ack=y+1 ─────────────────────────────> CLOSED
TIME_WAIT -- 等待 2MSL --> CLOSEDACK 与对端 FIN 有时可合并为三段,但典型情况下服务端收到 FIN 后可能仍有数据要发送,因此 ACK 和自己的 FIN 分开发出,表现为四次。
主动关闭方进入 TIME_WAIT 的目的:
- 若最终 ACK 丢失,可重新确认对端重传的 FIN;
- 等待旧报文在网络中自然消失,避免与后续使用相同四元组的新连接混淆。
HTTP Keep-Alive 与 TCP Keepalive
两者不是一回事:
- HTTP Keep-Alive / 持久连接:应用层概念,在一个 TCP 连接(或 HTTP/2/3 连接)上连续承载多个 HTTP 请求/响应,减少建连成本。HTTP/1.1 默认持久连接,除非声明
Connection: close。 - TCP Keepalive:操作系统 TCP 栈的保活探测。空闲很久后发送探测包,检测对端是否失联;时间参数常为系统配置,默认往往很长。它不是 HTTP 请求复用机制。
UDP 如何实现可靠传输
在应用层按业务选择性补齐 TCP 的能力:给消息编号、校验和分片,接收方 ACK/NACK、乱序重排和去重,发送方基于 RTT 超时重传和退避,还应实现流量/拥塞控制。简单的停等协议易理解但吞吐量低;实际协议通常采用滑动窗口和选择确认。QUIC 就是在 UDP 上实现可靠流、多路复用、加密和拥塞控制的代表。
HTTP/3 与 QUIC
QUIC 是基于 UDP 的加密传输协议,HTTP/3 在其上定义 HTTP 语义:
- 连接内有多个独立 stream,一个流的丢包不会阻塞其他流的有序交付;
- 集成 TLS 1.3,首次握手通常需 1-RTT,恢复连接可能 0-RTT(存在重放风险);
- 通过连接 ID 支持网络切换时的连接迁移;
- 有可靠传输、选择确认、丢失检测、流量控制与拥塞控制;IETF 标准 QUIC 不把早期 gQUIC 的 FEC 作为基础必备机制;
- 加密更多传输元数据,减少中间设备错误干预,但 UDP 可能被部分网络限制。