Skip to content

TCP、UDP 与 QUIC

TCP 与 UDP 的区别

维度TCPUDP
连接面向连接,通信前建立状态无连接,直接发送数据报
可靠性序号、确认、重传、校验保证可靠、有序字节流尽力而为;不保证送达、顺序、去重或重传
边界面向字节流,应用需要自行定义消息边界保留数据报边界
控制具备流量控制和拥塞控制协议本身没有;应用可自行实现
首部至少 20 字节,信息更丰富固定 8 字节
场景Web、数据库、文件传输、远程登录DNS、实时音视频、游戏、QUIC

UDP 的“快”来自协议开销和等待更少,不代表它没有拥塞问题或总是更低延迟。实时系统常在应用层接受部分丢包,或按业务需要添加可靠机制。

TCP 如何保证可靠性

  1. 序列号与累计确认(ACK):接收端确认“下一个期望的字节序号”,发送端据此判断已确认数据。
  2. 校验和:发现报文段在传输中损坏时丢弃,依赖重传恢复。
  3. 超时重传(RTO):未在估计超时时间内收到确认时重传,并基于 RTT 动态估计 RTO。
  4. 快速重传:收到多个重复 ACK(经典阈值为 3 个)通常推断有报文丢失,无需等待 RTO 即重传。
  5. 滑动窗口:允许连续发送多个未确认字节;乱序段可缓存、重复段可去重,从而实现有序交付。
  6. 流量控制与拥塞控制:分别保护接收方和网络。

流量控制:接收窗口

接收方在 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

三次握手使双方都确认初始序号,并建立双向收发能力:

  1. 客户端 SYN 表明客户端希望建立连接且其发送路径能到达服务器;
  2. 服务端 SYN+ACK 确认收到客户端 SYN,同时发出自己的 SYN;
  3. 客户端 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 --> CLOSED

ACK 与对端 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 可能被部分网络限制。

使用 Markdown 与 VitePress 构建