前言
TCP 和 UDP 都是传输层协议,都能解决:
1 | 把数据交给目标主机上的哪个进程。 |
但它们的取舍完全不同:
1 | TCP:连接、可靠、有序、字节流 |
再往后看,HTTP/3 又选择基于 QUIC,而 QUIC 基于 UDP。
这篇文章就围绕三件事展开:
- TCP 和 UDP 到底差在哪。
- 为什么 DNS、音视频、游戏常用 UDP。
- 为什么 QUIC / HTTP/3 会基于 UDP。
1. TCP 和 UDP 都属于传输层
IP 只能找到目标主机。
传输层要进一步解决:
1 | 目标主机上的哪个进程? |
这就是端口的作用。
TCP 有端口:
1 | 443:HTTPS |
UDP 也有端口:
1 | 53:DNS |
所以 TCP 和 UDP 的共同点是:
1 | 都通过端口把数据交给具体进程。 |
区别在于它们提供的传输能力不同。
2. TCP 的取舍:可靠、有序、成本更高
TCP 提供的是:
1 | 面向连接 |
TCP 会做很多事情:
1 | 三次握手建立连接 |
这让 TCP 很适合:
- 网页请求
- 文件下载
- 接口请求
- 邮件
- SSH
这些场景通常要求:
1 | 数据完整 |
代价是:
1 | 连接建立有成本 |
3. UDP 的取舍:简单、低延迟、应用自己控制
UDP 更简单。
UDP 报文主要包含:
1 | 源端口 |
UDP 不做:
1 | 不三次握手 |
它更像:
1 | 我把这个数据报发出去,后面你自己决定怎么处理。 |
这不是“低级版 TCP”,而是另一种取舍。
UDP 的优势是:
1 | 开销小 |
4. 字节流和数据报的区别
TCP 是字节流协议。
应用写入:
1 | write("Hello") |
接收方可能读到:
1 | HelloWorld |
也可能分几次读到:
1 | Hel |
TCP 不保留应用消息边界。
UDP 是数据报协议。
应用发送:
1 | send("A") |
接收方看到的是一个个数据报:
1 | A |
但这些数据报可能:
1 | 丢失 |
所以:
1 | TCP 保证连续字节流 |
5. 为什么 DNS 常用 UDP
DNS 查询通常很小。
比如:
1 | 问:example.com 的 IP 是什么? |
如果每次 DNS 查询都走 TCP,需要:
1 | 三次握手 |
成本更高。
UDP 可以直接:
1 | 发一个查询数据报 |
延迟更低,开销更小。
但 DNS 不是只能用 UDP。
这些情况可能用 TCP:
- 响应太大
- 区域传送
- DNS over TCP
- 一些安全或可靠性需求
6. 为什么音视频常用 UDP
实时音视频更怕:
1 | 卡顿 |
如果某一小段语音丢了,等它重传回来可能已经过时。
比如:
1 | 第 10 帧丢了 |
TCP 为了保证有序,可能会卡住后面的数据,等待第 10 帧重传。
但实时音视频可能更愿意:
1 | 跳过第 10 帧 |
所以音视频常用 UDP,然后在应用层自己做:
1 | 抖动缓冲 |
也就是说:
UDP 不是让应用什么都不管,而是把“哪些要补、哪些要跳过”的选择权交给应用。
7. 为什么游戏常用 UDP
游戏同步也很重视实时性。
比如玩家位置:
1 | 第 1 次位置:x = 10 |
如果第 1 次位置丢了,但第 2、第 3 次到了,旧位置可能已经没价值。
TCP 为了补旧包而卡住新状态,反而会让游戏体验更差。
所以游戏常用 UDP,把可靠性和同步策略交给应用层自己控制。
8. HTTP/2 的问题:TCP 层队头阻塞
HTTP/2 已经支持应用层多路复用。
它可以在一条 TCP 连接里同时传多个 HTTP Stream:
1 | Stream 1:HTML |
这些 Stream 可以交错发送。
但底层还是 TCP。
TCP 是可靠、有序的字节流。
一旦某个 TCP 包丢了:
1 | 包 1 到了 |
TCP 必须等包 2 重传成功,才能继续向上交付包 3、包 4。
所以:
1 | HTTP/2 解决了应用层请求排队 |
9. QUIC 为什么基于 UDP
如果 QUIC 基于 TCP,就很难绕开 TCP 的有序字节流限制。
TCP 的核心逻辑在操作系统内核里:
1 | 连接管理 |
应用层很难改变 TCP 的行为。
UDP 很薄,只提供:
1 | 端口 |
所以 QUIC 选择基于 UDP,在用户态自己实现:
1 | 连接管理 |
这句话很重要:
UDP 不可靠,但 QUIC 在 UDP 之上自己实现可靠。
10. QUIC 怎么改进多路复用
HTTP/2 的多个 Stream 共用一条 TCP 字节流。
如果 TCP 层丢包,所有 Stream 都可能被影响。
QUIC 也有 Stream,但 QUIC 的 Stream 在传输层实现。
如果某个 Stream 丢包:
1 | Stream 1 丢了一个包 |
QUIC 可以只阻塞 Stream 1,不影响 Stream 3、Stream 5 继续交付。
所以:
1 | HTTP/2:应用层多路复用,但底层是 TCP 单字节流 |
11. QUIC 建连为什么更快
HTTPS over TCP 通常需要:
1 | TCP 三次握手 |
连接握手和加密握手是两套流程。
QUIC 把传输握手和 TLS 1.3 加密握手整合在一起。
所以新连接通常可以更快开始传输数据。
对于已经连接过的服务,还可以使用 0-RTT:
1 | 更快发送早期数据 |
不过 0-RTT 有重放风险,不是所有请求都适合。
12. QUIC 为什么移动网络切换更稳
TCP 连接通常由四元组标识:
1 | 源 IP |
如果你从 Wi-Fi 切到 4G:
1 | 源 IP 变了 |
TCP 连接通常就断了,需要重连。
QUIC 使用 Connection ID 标识连接。
即使网络切换导致 IP 和端口变化,只要 Connection ID 还有效,QUIC 就可以尝试保持连接迁移。
这对移动设备很重要。
13. 为什么不是所有东西都用 QUIC
QUIC 很强,但不是没有成本。
它带来:
1 | 实现复杂 |
所以现实中常见是:
1 | HTTP/1.1、HTTP/2、HTTP/3 共存 |
浏览器会根据服务端支持情况协商使用哪个版本。
14. TCP、UDP、QUIC 对比
| 对比 | TCP | UDP | QUIC |
|---|---|---|---|
| 所在层次 | 传输层 | 传输层 | 基于 UDP 的传输协议 |
| 连接 | 面向连接 | 无连接 | 有连接概念 |
| 可靠性 | 保证可靠 | 不保证 | 自己实现可靠 |
| 顺序 | 保证字节流有序 | 不保证 | Stream 内有序,Stream 间更独立 |
| 数据形态 | 字节流 | 数据报 | Stream + 数据报底座 |
| 多路复用 | TCP 本身不懂 HTTP Stream | 无 | 原生支持多 Stream |
| 加密 | 依赖 TLS | 无内置 | 集成 TLS 1.3 |
| 典型场景 | HTTP/1.1、HTTP/2、文件传输 | DNS、音视频、游戏 | HTTP/3 |
15. 一句话总结
可以这样记:
1 | TCP:帮你把可靠、有序做好,但成本更高。 |
HTTP 演进也可以这样看:
1 | HTTP/1.1:多个请求容易排队 |
最短记法:
QUIC 不是相信 UDP 可靠,而是利用 UDP 简单,把现代传输能力自己做了一遍。