网络协议是后端工程师的「内功」——框架用得再熟,不懂 TCP/IP 也是花架子。本篇整理 TCP 与 UDP 两大传输层协议:从 OSI 七层模型到 TCP 三次握手 / 四次挥手状态机,再到 SYN 攻击防御与 TCP/UDP 选型实战。
一、网络分层模型
1.1 OSI 七层 vs TCP/IP 四层

| OSI 七层 | TCP/IP 四层 | 对应协议 |
|---|---|---|
| 应用层 | 应用层 | HTTP、FTP、DNS、SMTP、SSH、SNMP |
| 表示层 | (合并到应用层) | SSL/TLS、JPEG、ASCII |
| 会话层 | (合并到应用层) | RPC、SOCKS |
| 传输层 | 传输层 | TCP、UDP |
| 网络层 | 网络层 | IP、ICMP、ARP、OSPF |
| 数据链路层 | 网络接口层 | PPP、Ethernet、MAC |
| 物理层 | (合并到网络接口层) | 网线、光纤、电波 |
TCP/IP 模型把 OSI 的 7 层合并为 4 层:表示层和会话层并入应用层,物理层并入网络接口层。本篇的主角 TCP / UDP 都在传输层——往下借 IP 协议跨网络传数据,往上为应用层提供端到端通信。
1.2 分层的本质:解耦
每一层只关心本层的协议,把数据封装后交给下一层:
应用层 data
↓ 加 TCP/UDP 头
传输层 segment
↓ 加 IP 头
网络层 packet
↓ 加帧头帧尾
网络接口层 frame
↓ 比特流
物理层 bit
收方反向解封装——这就是网络协议栈的核心。TCP/IP 之所以能成为互联网事实标准,本质是因为它把复杂问题分层拆解得足够干净。
二、TCP 协议
TCP(Transmission Control Protocol) 是面向连接、可靠、基于字节流的传输层协议。
三大核心特征:
| 特征 | 含义 | 实现机制 |
|---|---|---|
| 面向连接 | 通信前先建立连接(三次握手),通信结束释放连接(四次挥手) | 状态机 |
| 可靠 | 不丢包、不乱序、不重复 | 序列号 + 确认号 + 重传 + 滑动窗口 |
| 字节流 | 应用层数据无边界,TCP 看到的是连续字节 | MSS 分段 |
2.1 TCP 头部关键字段
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Port | Destination Port |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Sequence Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Acknowledgment Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Data | |U|A|P|R|S|F| |
| Offset| Reserved |R|C|S|S|Y|I| Window |
| | |G|K|H|T|N|N| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Checksum | Urgent Pointer |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
记住几个最关键字段:
- 源端口 / 目的端口(各 16 位)——寻址到进程
- 序列号 seq(32 位)——保证有序、可靠
- 确认号 ack(32 位)——期望收到的下一个字节号
- 9 个标志位——
SYN/ACK/FIN/RST/PSH/URG/ …… - 窗口大小(16 位)——滑动窗口 流控
2.2 TCP 的十一种状态
TCP 状态机是面试和实战的核心——
netstat -an输出的就是这套状态。
+---------+
| CLOSED | ← 客户端起点
+---------+
| active open
| 发 SYN
v
+---------+
| SYN_SENT |
+---------+
| 收 SYN+ACK, 发 ACK
v
+---------+
+----------------------|ESTABLISHED|---------------+
| +---------+ |
| active close | passive close
| 发 FIN | 收 SYN, 发 SYN+ACK
v v
+---------+ +---------+
|FIN_WAIT1| | SYN_RCVD|
+---------+ +---------+
| 收 ACK | 收 ACK
v v
+---------+ +---------+
|FIN_WAIT2| <-- 半关闭 --> |ESTABLISHED|
+---------+ +---------+
| 收 FIN, 发 ACK | active close, 发 FIN
v v
+---------+ +---------+
|TIME_WAIT| |CLOSE_WAIT|
+---------+ +---------+
| 2MSL 后 | 收 FIN, 发 ACK
v v
+---------+ +---------+
| CLOSED | | LAST_ACK|
+---------+ +---------+
| 收 ACK
v
+---------+
| CLOSED | ← 服务端终点
+---------+
核心状态速查:
| 状态 | 谁进入 | 含义 |
|---|---|---|
SYN_SENT | 主动连接方 | 已发 SYN,等 SYN+ACK |
SYN_RCVD | 被连接方 | 收到 SYN,回 SYN+ACK,等 ACK |
ESTABLISHED | 双方 | 连接建立,可以传数据 |
FIN_WAIT1 | 主动关闭方 | 已发 FIN,等 ACK |
FIN_WAIT2 | 主动关闭方 | 收到对端 ACK,等对端 FIN(半关闭) |
CLOSE_WAIT | 被动关闭方 | 收到对端 FIN,回 ACK,等应用层 close() |
LAST_ACK | 被动关闭方 | 应用层已 close,发 FIN,等最后一个 ACK |
TIME_WAIT | 主动关闭方 | 已发最后 ACK,等 2MSL 才进 CLOSED |
2.3 TCP 建立连接:三次握手

三次握手就是指建立一个 TCP 连接时,客户端和服务器总共需要发送三个包。主要作用是确认双方的接收能力和发送能力是否正常、指定自己的初始化序列号 ISN 为后面的可靠性传送做准备。
刚开始客户端处于 CLOSED 状态,服务端处于 LISTEN 状态。
第一次握手
客户端给服务端一个 SYN 报文,指明客户端的初始化序列号
ISN(c),此时客户端处于SYN_SENT状态。首部的同步位SYN=1,初始序列号seq=x,SYN=1 的报文不能携带数据,但是要消耗一个序号。
Client → Server: SYN=1, seq=x
第二次握手
服务端收到客户端的 SYN 报文,会以自己的 SYN 报文应答,也指定自己的初始化序列号
ISN(s),同时把客户端的序列号 +1 作为 ACK 的值,标识自己已收到客户端 SYN,此时服务端处于SYN_RCVD状态。
Server → Client: SYN=1, ACK=1, seq=y, ack=x+1
第三次握手
客户端收到 SYN 报文后,发送一个 ACK 报文,把服务端的序列号 +1 作为 ACK,表示收到了服务端 SYN 报文。此时客户端处于
ESTABLISHED状态,服务端收到 ACK 报文后也处于ESTABLISHED状态,双方建立起连接。
Client → Server: ACK=1, seq=x+1, ack=y+1
三次握手汇总
| 次数 | 方向 | 标志位 | seq | ack | Client 状态 | Server 状态 |
|---|---|---|---|---|---|---|
| 1 | C → S | SYN | x | — | SYN_SENT | LISTEN |
| 2 | S → C | SYN+ACK | y | x+1 | SYN_SENT | SYN_RCVD |
| 3 | C → S | ACK | x+1 | y+1 | ESTABLISHED | ESTABLISHED |
2.4 为什么是三次?不是两次?
这是最经典的面试题——核心答案:三次是确认双方收发能力的最小次数。
逐次分析能力确认:
| 次数 | 谁发包 | 谁收到 | 能确认什么 |
|---|---|---|---|
| 第一次 | Client 发 | Server 收 | Server 知道:Client 发送正常、Server 接收正常 |
| 第二次 | Server 发 | Client 收 | Client 知道:Server 收发正常、Client 收发正常(全部确认) 但 Server 还不知道 Client 接收是否正常 |
| 第三次 | Client 发 | Server 收 | Server 知道:Client 接收正常、Server 发送正常(全部确认) |
两次握手时,Server 在第二次发包后立即进入
ESTABLISHED分配资源——但 Server 永远无法确认 Client 的接收能力。如果第二次包丢了,Server 一厢情愿地保持着连接,浪费资源。
另一个理由:防止历史连接
RFC 793 给出的根本原因:防止「已失效的连接请求」突然又传到了服务端,造成资源浪费。
场景:两次握手时
1. Client 发 SYN₁,网络拥塞滞留
2. Client 超时重发 SYN₂,建立连接、传数据、关闭
3. SYN₁ 终于到了 Server
4. Server 以为是新请求,直接回 SYN+ACK 进 ESTABLISHED —— 但 Client 根本没想连
5. 这个连接一直挂着,浪费 Server 资源
三次握手下,Client 收到 SYN+ACK 时会检查 seq,发现不对就发 RST 终止。
2.5 三次握手过程中可以携带数据吗
第三次握手的时候,是可以携带数据的。但是,第一次、第二次握手不可以携带数据。
为什么第一次不能携带?
假如第一次握手可以携带数据,攻击者每次都在 SYN 报文中放入大量数据,疯狂重复发送——Server 会花费大量时间、内存空间来接收报文,瞬间被攻击瘫痪。
而第三次握手时,Client 已经处于 ESTABLISHED 状态——它已经确认了 Server 的收发能力,这时携带数据是安全的。
这其实是早期 HTTP 优化 TCP Fast Open(TFO,RFC 7413)的核心思路——把数据塞进 SYN 包,省一个 RTT。Google 2014 年提出,Linux 3.6 内核支持。
2.6 SYN 攻击
服务器端的资源分配是在二次握手时分配的,而客户端的资源是在完成三次握手时分配的——所以服务器容易受到 SYN 洪泛攻击。
攻击原理
SYN 攻击就是 Client 在短时间内伪造大量不存在的 IP 地址,向 Server 不断发送 SYN 包。Server 回复确认包并等待 Client 确认——由于源地址不存在,Server 需要不断重发直至超时。这些伪造的 SYN 包长时间占用未连接队列,导致正常的 SYN 请求因为队列满而被丢弃,引起网络拥塞甚至系统瘫痪。
SYN 攻击是一种典型的 DoS/DDoS 攻击。
检测
当你在服务器上看到大量的半连接状态(
SYN_RCVD),特别是源 IP 地址是随机的,基本上可以断定这是一次 SYN 攻击。
# Linux 检测 SYN 攻击
netstat -n -p TCP | grep SYN_RECV
四种防御方法
| 方法 | 思路 | 优劣 |
|---|---|---|
| 缩短 SYN Timeout | 减少半连接保留时间(如 60s → 10s) | ⚠️ 影响弱网正常用户 |
| 增加最大半连接数 | 调大 tcp_max_syn_backlog | ⚠️ 治标不治本,内存换安全 |
| 过滤网关防护 | 防火墙代理 SYN(自身当中间人) | ✅ 有效但增加延迟 |
| SYN Cookies | Server 不分配资源,把状态编码进 seq 返回 | ✅ 最佳方案,下文展开 |
SYN Cookies 技术原理
Server 收到 SYN 时不分配资源,而是精心构造一个 seq(基于时间、MSS、客户端 IP/Port、Server 密钥计算的 Hash)发给 Client。
- 如果 Client 是真用户,会回 ACK,且
ack-1正是之前的 seq——Server 用密钥验签通过,这时才分配资源- 如果 Client 是攻击者(伪造 IP),永远不会回 ACK,Server 一点资源都没浪费
Linux 默认开启:
sysctl net.ipv4.tcp_syncookies = 1。
2.7 TCP 释放连接:四次挥手

建立连接需要三次握手,终止连接要经过四次挥手。这由 TCP 的半关闭(half-close) 造成——TCP 提供了一端结束发送后还能接收的能力。
TCP 连接的拆除需要发送四个包,称为 Four-way handshake,客户端或服务器均可主动发起。
第一次挥手
客户端发送一个 FIN 报文,报文中指定一个序列号。此时客户端处于
FIN_WAIT1状态。
Client → Server: FIN=1, seq=u
发出连接释放报文段(FIN=1,序号 seq=u),停止发送数据,主动关闭 TCP 连接,进入 FIN_WAIT1(终止等待 1)状态,等待服务端确认。
第二次挥手
服务端收到 FIN 之后,会发送 ACK 报文,且把客户端的序列号值 +1 作为 ACK 报文的序列号值。此时服务端处于
CLOSE_WAIT状态。
Server → Client: ACK=1, seq=v, ack=u+1
服务端收到连接释放报文段后发出确认报文段(ACK=1,确认号 ack=u+1,序号 seq=v),进入 CLOSE_WAIT(关闭等待)状态。
此时的 TCP 处于半关闭状态——客户端到服务端的连接释放。客户端收到服务端的确认后,进入
FIN_WAIT2(终止等待 2)状态,等待服务端发出的连接释放报文段。
第三次挥手
服务端也想断开连接时,发给 FIN 报文,且指定一个序列号。此时服务端处于
LAST_ACK状态。
Server → Client: FIN=1, ACK=1, seq=w, ack=u+1
服务端数据发完后,发出连接释放报文段(FIN=1,ACK=1,序号 seq=w,确认号 ack=u+1),进入 LAST_ACK(最后确认)状态,等待客户端确认。
第四次挥手
客户端收到 FIN 之后,发送一个 ACK 报文作为应答,且把服务端的序列号值 +1 作为自己 ACK 报文的序列号值。此时客户端处于
TIME_WAIT状态。
Client → Server: ACK=1, seq=u+1, ack=w+1
客户端收到服务端的连接释放报文段后,对此发出确认报文段(ACK=1,seq=u+1,ack=w+1),进入 TIME_WAIT(时间等待)状态。
需要过一阵子(2MSL)以确保服务端收到自己的 ACK 报文之后才会进入 CLOSED 状态。服务端收到 ACK 报文后立即进入 CLOSED 状态。
四次挥手汇总
| 次数 | 方向 | 标志位 | seq | ack | Client 状态 | Server 状态 |
|---|---|---|---|---|---|---|
| 1 | C → S | FIN | u | — | FIN_WAIT1 | ESTABLISHED |
| 2 | S → C | ACK | v | u+1 | FIN_WAIT2 | CLOSE_WAIT |
| 3 | S → C | FIN+ACK | w | u+1 | FIN_WAIT2 | LAST_ACK |
| 4 | C → S | ACK | u+1 | w+1 | TIME_WAIT | CLOSED |
| 2MSL 后 | — | — | — | — | CLOSED | — |
关键观察:客户端执行主动关闭并进入
TIME_WAIT是正常的,服务端通常执行被动关闭,不会进入TIME_WAIT状态。
在 socket 编程中,任何一方执行
close()操作即可产生挥手动作。
2.8 为什么是四次?
建立连接时三次就够了,关闭却要四次——核心区别在于 Server 收到 SYN 后可以立即发 SYN+ACK(ACK 应答 + SYN 同步合一)。
但关闭时,Server 收到 FIN 后很可能还有数据没发完——所以只能先回一个 ACK「FIN 收到了」,等数据发完才能发自己的 FIN。ACK 和 FIN 必须分两次发,所以多了一次。
握手时: 挥手时:
SYN → FIN →
← SYN+ACK ← ACK (Server 还有数据要发)
ACK → ← FIN (数据发完了)
ACK →
2.9 TIME_WAIT 与 2MSL
TIME_WAIT状态也称为 2MSL 等待状态。每个具体 TCP 实现必须选择一个报文段最大生存时间 MSL(Maximum Segment Lifetime),它是任何报文段被丢弃前在网络内的最长时间。
当 TCP 执行一个主动关闭,并发回最后一个 ACK,该连接必须在
TIME_WAIT状态停留 2 倍 MSL。
为什么是 2MSL?两个原因
原因一:保证最后的 ACK 能到达
假设客户端不等待 2MSL,而是在发送完 ACK 之后直接关闭——一旦这个 ACK 丢失,处于
LAST_ACK状态的服务端收不到对 FIN-ACK 的确认,会超时重传 FIN-ACK,但客户端已经关了,无法重传 ACK——服务端永远进不了CLOSED状态。
正常流程:
Client --ACK--> Server (Server 进入 CLOSED)
ACK 丢失的情况:
Client --ACK lost--> Server
Server --FIN-ACK--> Client (超时重传)
Client --ACK--> Server (再次确认,重启 2MSL 计时器)
Server 进入 CLOSED
原因二:让旧连接的报文在网络中消亡
2MSL 期间,本次连接的所有报文都会因 TTL 到期而从网络中消失——避免它们干扰下一个复用相同四元组(src_ip, src_port, dst_ip, dst_port)的新连接。
MSL 在 Linux 下默认 30 秒,所以
TIME_WAIT持续 60 秒。
TIME_WAIT 过多的代价
高并发服务器(如 Nginx 反向代理)容易积累大量
TIME_WAIT——每个TIME_WAIT占用一个五元组。如果短连接太多,端口耗尽(默认 28232 个可用端口)就拒绝新连接。
生产环境优化:
# 允许将 TIME_WAIT 重用为新的连接
sysctl -w net.ipv4.tcp_tw_reuse=1
# 开启 keepalive,减少短连接(更推荐)
sysctl -w net.ipv4.tcp_keepalive_time=600
# 调小 TIME_WAIT 持续(不推荐,可能影响可靠性)
# sysctl -w net.ipv4.tcp_fin_timeout=15
关键认知:
tcp_tw_reuse=1是客户端优化(用时间戳判断报文新旧,可安全复用 TIME_WAIT 端口);tcp_tw_recycle=1在 NAT 环境下会丢包,Linux 4.12 已删除该选项。
三、UDP 协议
UDP(User Datagram Protocol) 是无连接、不可靠、基于数据报的传输层协议。
⚠️ 原笔记标题虽然写了「TCP 与 UDP」,但内容只有 TCP。本节是补全——UDP 是另一个传输层主力,DNS、视频直播、游戏服务器、IoT 全在用它。
3.1 UDP 头部:极简 8 字节
0 7 8 15 16 23 24 31
+--------+--------+--------+--------+
| Source | Destination |
| Port | Port |
+--------+--------+--------+--------+
| | |
| Length | Checksum |
| | |
+--------+--------+--------+--------+
| data octets ...
+----------------...
对比 TCP 头部 20 字节起,UDP 只有 8 字节——没有序列号、没有 ACK、没有窗口、没有状态机。UDP 把「可靠」丢给应用层去解决。
3.2 UDP 的四大特性
| 特性 | 含义 | 对应的应用场景 |
|---|---|---|
| 无连接 | 不需要握手,发就完了 | DNS 查询(一问一答) |
| 不可靠 | 不保证送达、不保证顺序 | 视频流(丢几帧无所谓) |
| 面向报文 | 应用层发什么,UDP 就发什么,不拆分不合并 | 简单协议设计 |
| 没有拥塞控制 | 网络拥塞时不会主动减速 | 实时游戏(宁愿丢包不要延迟) |
3.3 UDP 适用场景
| 场景 | 选用 UDP 的原因 |
|---|---|
| DNS 查询 | 一问一答,建立 TCP 连接开销太大 |
| DHCP | 客户端还没 IP,没法建 TCP 连接 |
| 视频直播 / 语音通话 | 实时性 > 完整性,丢帧比延迟好(WebRTC 基于 UDP) |
| 在线游戏 | 玩家位置每秒 30 次同步,旧数据丢掉无所谓 |
| SNMP / 监控指标 | 频繁小数据包,TCP 握手开销大 |
| IoT / CoAP | 设备资源紧张,UDP 头部开销小 |
| 组播 / 广播 | TCP 是点对点,不支持一对多 |
关键观察:TCP 适合「数据要完整」的场景,UDP 适合「实时性优先、丢点数据无所谓」的场景。
3.4 UDP 的「不可靠」要怎么用
既然 UDP 不可靠,那应用层怎么保证可靠性?答案是应用层自己实现——这是 QUIC / HTTP/3 的设计哲学。
| 需求 | TCP 怎么做 | UDP 应用层怎么做 |
|---|---|---|
| 不丢包 | TCP 序列号 + 重传 | 应用层自己加 seq + ACK + 超时重传 |
| 不乱序 | TCP 按序列号重组 | 应用层加 seq,接收方重排 |
| 流控 | TCP 滑动窗口 | 应用层自定义(如 QUIC 用 BBR) |
| 拥塞控制 | TCP 拥塞窗口( Reno/CUBIC/BBR) | 应用层自定义(QUIC 自带) |
为什么要重复造轮子? 因为 TCP 的实现在内核态,改不动——内核升级周期 5-10 年;而 UDP 把控制权完全交给了应用层,3 个月就能迭代一个新算法。这是 QUIC 诞生的根本动机。
四、TCP vs UDP 全面对比
| 维度 | TCP | UDP |
|---|---|---|
| 连接 | 面向连接(三次握手) | 无连接 |
| 可靠性 | 可靠(ACK + 重传) | 不可靠(尽最大努力) |
| 有序性 | 保证有序 | 不保证有序 |
| 传输方式 | 字节流 | 数据报 |
| 头部开销 | 20 字节起 | 8 字节 |
| 流量控制 | 有(滑动窗口) | 无 |
| 拥塞控制 | 有(Reno / CUBIC / BBR) | 无 |
| 广播 / 组播 | 不支持 | 支持 |
| 状态机 | 11 种状态 | 无状态 |
| 典型协议 | HTTP/1/2、HTTPS、SSH、SMTP、FTP | DNS、DHCP、SNMP、NTP、WebRTC、QUIC |
| 典型应用 | 网页、邮件、文件传输、数据库 | DNS 查询、视频直播、游戏、IoT |
选型口诀
- 要可靠、要有序、要稳——选 TCP(金融、文件、消息)
- 要快、要实时、能容忍丢包——选 UDP(直播、游戏、DNS)
- 要在 TCP 之上做应用层协议——选 TCP(HTTP、Redis 协议)
- 要一对多分发——选 UDP 组播(直播推流、股票行情)
五、协议在框架中的体现
| 框架 / 协议 | 基于 TCP 还是 UDP | 为什么 |
|---|---|---|
| HTTP/1.1、HTTP/2 | TCP | 网页要完整,不能丢字节 |
| HTTP/3 | UDP(QUIC) | 解决 TCP 队头阻塞 + 加速握手 |
| WebSocket | TCP | 双向可靠通信 |
| gRPC | TCP(HTTP/2) | 复用 HTTP/2 多路复用 |
| Dubbo 默认 | TCP | RPC 要可靠 |
| Redis 协议 RESP | TCP | 命令必须完整到达 |
| Kafka / RabbitMQ | TCP | 消息不能丢 |
| MySQL 协议 | TCP | SQL 执行结果不能错 |
| DNS | UDP(查询)+ TCP(区域传输 / 长响应) | 小包用 UDP 省握手,大包 / 可靠传输用 TCP |
| DHCP | UDP | 客户端还没 IP,没法 TCP |
| NTP | UDP | 频繁小包,握手开销大 |
| WebRTC | UDP | 实时音视频,延迟敏感 |
| QUIC | UDP | HTTP/3 的底座,Google 出品 |
→ Dubbo 这种 RPC 框架为什么默认 TCP?详见 Dubbo 架构与三种调用方式;Nginx 处理大量 TCP 短连接如何应对 TIME_WAIT?详见 Nginx 性能原理与配置。
六、实战排错:状态机是工具
排查 TCP 问题时,
netstat/ss看状态分布比看日志更直接:
| 现象 | 大量堆积的状态 | 可能原因 |
|---|---|---|
应用没及时 close() | CLOSE_WAIT 堆积 | 业务代码 bug——异步任务没结束 / 异常没关连接 |
| 主动关闭方资源耗尽 | TIME_WAIT 堆积 | 短连接频繁建立——加 keepalive 或换长连接 |
| 受到 SYN 攻击 | SYN_RCVD 堆积 | 检查源 IP 是否随机 / 开 SYN Cookies |
| 服务端监听出问题 | 大量 SYN_SENT | 服务端宕机或 backlog 满 |
| 防火墙丢包 | 卡在 SYN_SENT | 安全组 / iptables 没放端口 |
# 统计各状态连接数(按状态分组)
netstat -an | awk '/^tcp/ {++S[$NF]} END {for(s in S) print s, S[s]}'
# 看具体某个端口的连接
ss -antp | grep ':8080'
# 抓 TCP 包分析
tcpdump -i any -n 'port 8080' -w /tmp/conn.pcap
七、小结
TCP 与 UDP 是传输层两大主力——一个为可靠而生,一个为简单而活。
- TCP:三次握手建立连接 → 字节流可靠传输 → 四次挥手释放连接。核心复杂度在状态机和可靠性保障
- UDP:无连接、不可靠、轻量级。核心价值在简单和实时
互联网 30 年来都建立在「应用跑在 TCP 上」这个假设上——但 HTTP/3 / QUIC 正在改写这个假设,UDP 终于迎来了自己的时代。
现代视角补一句(2026):TCP/UDP 协议本身从 1981 年 RFC 793 / 768 定稿以来,协议字段一字未改。变化的是:
- 拥塞控制算法从 Reno → CUBIC → BBR(Google 2016 提出,Linux 4.9 默认),带宽利用率提升数倍
- QUIC(RFC 9000,2021)把 TCP 的可靠传输搬到 UDP 之上,0-RTT 握手让网页加载快 30%+
- HTTP/3(RFC 9114,2022)全面基于 QUIC,Chrome / Cloudflare / 主流大厂已经默认启用
- eBPF 让内核 TCP 算法可以在用户态动态替换,告别「内核版本绑定拥塞算法」的时代
但底层 IP / TCP / UDP 三层不动——分层架构的力量,就在于此:底层稳定,上层迭代。
下一篇推荐:Nginx 性能原理与配置——Nginx 作为应用层,是如何基于 epoll + TCP 处理百万并发的。