TCP-UDP与前端工程师需要掌握的网络基础
TCP 可靠有序、UDP 快但不可靠,是传输层两根顶梁柱。三次握手、四次挥手、拥塞控制, 以及 HTTP/3 为何基于 QUIC/UDP,是前端网络与性能面试的高频题。
一句话概括
TCP 和 UDP 是传输层的两大协议,一句话区分:TCP 像挂号信——可靠、有序、不丢;UDP 像明信片——扔出去就不管了,快但可能丢。HTTP、WebSocket 走 TCP(不能丢一个字节),DNS、直播、游戏走 UDP(晚到的不如丢了重来)。
前端之所以要懂,是因为它直接影响性能:每次新建 HTTP/1.1 连接都要 TCP 三次握手(+TLS 握手)吃 1–3 个 RTT,而连接复用、HTTP/2、HTTP/3(QUIC/UDP)本质上都在和”握手成本 + 队头阻塞”较劲。面试常问握手挥手、二者区别、HTTP/3 为什么换 UDP。
核心知识点
1. TCP 的四大特征
1
2
3
4
可靠传输:确认 ACK + 超时重传 + 序列号(丢了我给你重发)
有序交付:按序号重组,重复的丢掉
流量控制:滑动窗口——接收方缓冲区满了就告诉发送方"先别发"
拥塞控制:慢启动 → 拥塞避免 → 快速重传/恢复(网络堵了主动降速)
代价:连接建立慢(三次握手)、头部大(最小 20 字节)、有重传和控速开销。
2. UDP 的特征
1
2
3
4
无连接:不用握手,直接发
不可靠:无 ACK、无重传、可能乱序/丢包
无流量/拥塞控制:发方随便发,接收方 buffer 满就丢
低开销:头部仅 8 字节(TCP 最小 20)
代价是可能丢、可能乱,但延迟极低——实时音视频、游戏、DNS 查询都吃这套。
3. 三次握手:为什么不是两次
1
2
3
4
客户端 服务器
│── SYN, seq=x ───────────→│ ① 客户端:"我想连,我的起始序号 x"
│←── SYN, ACK, seq=y, ack=x+1 ─│ ② 服务器:"收到,我也就绪,确认你的 x+1"
│── ACK, ack=y+1 ────────→│ ③ 客户端:"收到你的确认,连接建立"
为什么必须三次?两次握手有坑:
1
2
3
两次的话:客户端发的 SYN 半路丢了 → 客户端不知道,服务器却以为连上了
服务器分配资源、干等数据 → 客户端永远不说话 → 资源白占
三次的本质:双方都确认了"我能发 + 你能收"这一双向能力,少一次不够,多一次浪费
对前端的影响:每建一条新 TCP 连接 ≈ 1–3 个 RTT(30–200ms)。HTTP/1.1 开多个连接、每次都握手,很贵;HTTP/2 和 WebSocket 复用一条连接就避开了重复握手。
4. 四次挥手:为什么比握手多一次
1
2
3
4
5
6
7
客户端 服务器
│── FIN, seq=u ──────────→│ ① 客户端:"我发完了,关我的写通道"
│←── ACK, ack=u+1 ───────│ ② 服务器:"收到"(但可能还有数据没发完)
│ │ …服务器继续把剩余数据发完…
│←── FIN, seq=w ─────────│ ③ 服务器:"我也发完了,关我的写通道"
│── ACK, ack=w+1 ───────→│ ④ 客户端:"收到,连接关闭"
│ 客户端等 2MSL 才释放(防最后一个 ACK 丢失)
关键差异:握手时双方同时准备好,SYN 和 SYN-ACK 能合并节奏;挥手时服务器收到 FIN 后可能还有数据要发,得先回 ACK、发完数据再发 FIN,所以多了一步变成四次。
5. 各协议到底跑在 TCP 还是 UDP 上
| 应用 | 传输层 | 理由 |
|---|---|---|
| HTTP/1.1、HTTP/2 | TCP | 需要可靠、有序的请求-响应 |
| WebSocket | TCP | 双向流要可靠 |
| HTTP/3(QUIC) | UDP | 在 UDP 上自建可靠传输,解决 TCP 队头阻塞 |
| DNS(通常) | UDP | 快,响应小;超 512 字节/区域传输才 fallback TCP |
| WebRTC 音视频 | UDP | 实时,晚到的包不如丢了 |
| 直播推流 | UDP/QUIC | 实时优先 |
HTTP/3 为什么换 UDP? TCP 的队头阻塞是”连接级”的:一个包丢了,同连接上所有 HTTP 流都卡住等重传。QUIC 在 UDP 上自己实现可靠传输,把拥塞控制和重传做到流级别——某个流丢包只影响它自己,其他流照跑。还能 0-RTT 恢复会话(再次访问几乎零握手成本)。
1
2
3
4
5
6
7
8
// WebSocket 底层就是 TCP 三次握手(浏览器自动干)
const ws = new WebSocket('wss://echo.websocket.org');
ws.onopen = () => console.log('TCP 连接已建立,可以发消息了');
ws.onmessage = e => console.log(e.data);
ws.onclose = e => {
// 1000 正常关闭 / 1001 服务端关闭 / 1006 网络异常断开
if (e.code === 1006) setTimeout(() => ws.reconnect?.(), 1000); // 异常断线要重连
};
其实你每天都在用
- 每次打开网页:HTTP/1.1 先 TCP 三次握手再 TLS,首屏那点延迟里有握手的一份
keep-alive/ HTTP/2 复用连接:避免每个请求都重新三次握手,省的就是 RTT- WebSocket 实时聊天:底层 TCP 长连接,断了要自己写重连(看 close code 1006)
- DNS 解析:走 UDP 53 端口,所以飞快;偶尔大响应才切 TCP
- 看直播 / 视频会议:实时音视频走 UDP,丢几帧比卡 500ms 强
- HTTP/3 访问 Google/YouTube/Cloudflare:你已经在用 QUIC/UDP 了,只是无感
- 弱网下接口变慢:可能是 TCP 丢包触发重传 + 拥塞窗口减半,连接被”拖慢”
常见误解(FAQ)
❌ 误区一:”UDP 不可靠,所以不如 TCP,能不用就不用”
看场景。网页、文件要可靠,用 TCP 没错;但实时音视频、游戏、DNS 查询,晚到 500ms 的数据毫无意义,反而要”快、宁可丢”。UDP 的低延迟正是这些场景的刚需,不是缺陷。
❌ 误区二:”两次握手就能建立连接,三次是浪费”
两次握手下,丢失的 SYN 会让服务器误以为连接已建、白分配资源干等,客户端却永远不发数据。三次是为了双向确认收发能力,少一次有资源泄漏风险,多一次纯属多余。
❌ 误区三:”挥手四次、握手三次,说明关连接比建连接麻烦”
本质区别在时机:握手时双方同时就绪,可一气呵成;挥手时被动方(服务器)收到 FIN 后可能还有数据没发完,必须先 ACK、发完再 FIN,于是多一步。不是”更麻烦”,是”被动方需要时间收尾”。
❌ 误区四:”HTTP/3 用 UDP 就是变回不可靠了”
恰恰相反。QUIC 在 UDP 之上自己实现了可靠、有序、拥塞控制,等于”用 UDP 重新造了一个更好的 TCP”,只是把队头阻塞隔离到流级别、并能 0-RTT 建连。可靠性没丢,性能和连接迁移反而更强。
一句话总结
TCP 用三次握手、重传、拥塞控制换来”可靠有序”,代价是握手成本和队头阻塞;UDP 舍弃可靠换极低延迟,喂饱实时场景。HTTP/1.1·2 活在 TCP 上、HTTP/3 借 QUIC 上 UDP——理解这对”可靠 vs 速度”的取舍,网络层面试就通透了。