1. UDP 协议基础:报文结构、端口号与 Socket、UDP 与 TCP 核心区别
各位好,我是老周。做网络排查十几年,UDP 这玩意儿让我又爱又恨。爱它简单直接,恨它出了问题连个招呼都不打。今天咱们就从最底层开始,把 UDP 的底裤扒干净。
说白了,UDP 就是网络世界里的「明信片」。你写好内容,贴上邮票(端口号),扔进邮筒(IP 网络),对方能不能收到、收到后顺序对不对,你一概不知。但正因为这种「不负责任」,它才跑得飞快。
1.1 UDP 报文结构:轻到只有 8 字节
UDP 头部有多轻?我算给你看:源端口 2 字节、目的端口 2 字节、长度 2 字节、校验和 2 字节。就 8 个字节,没了。
对比一下 TCP 头部,最少 20 字节,带选项能到 60 字节。UDP 省下来的每一比特,都变成了有效载荷的传输效率。
| 字段 | 长度 | 说明 |
|---|---|---|
| 源端口 | 16 bit | 发送方端口,可选填(可设为 0) |
| 目的端口 | 16 bit | 接收方端口,必填 |
| 长度 | 16 bit | UDP 头部 + 数据的总长度,最小 8 |
| 校验和 | 16 bit | 覆盖头部和数据,可选(IPv4 下可填 0) |
这里有个细节很多人忽略:UDP 长度字段的最小值是 8。如果收到一个长度小于 8 的 UDP 报文,接收端会直接丢弃。嗯,这是协议规定的硬性门槛。
1.2 端口号与 Socket:UDP 的「门牌号」
端口号的作用很简单——让操作系统知道这个数据包该交给哪个应用程序。UDP 端口号范围是 0~65535,其中 0~1023 是知名端口,需要管理员权限才能绑定。
我个人习惯把端口号分成三类:
- 知名端口(0-1023):DNS 用 53,DHCP 用 67/68,SNMP 用 161/162。这些端口别乱占。
- 注册端口(1024-49151):很多应用层协议用这个范围,比如 NTP 用 123,RTP 用动态端口。
- 动态/私有端口(49152-65535):客户端临时用,用完就释放。
UDP Socket 是什么?说白了就是 IP 地址 + 端口号 的组合。一个 UDP Socket 唯一标识了网络中的一个通信端点。
关键区别: TCP Socket 是面向连接的,一个 Socket 对应一个确定的远程端点。UDP Socket 是无连接的,同一个 Socket 可以跟任意远程端点通信。你想想看,这意味着一台服务器上的 UDP Socket 可以同时服务成千上万个客户端,而 TCP 每个连接都需要一个独立的 Socket。
写代码时,UDP 的 Socket 操作比 TCP 简单得多:
// UDP 服务端核心代码(Python 示例)
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(('0.0.0.0', 8888))
while True:
data, addr = sock.recvfrom(1024) # 一次 recvfrom 就是一个完整报文
print(f"收到来自 {addr} 的数据: {data}")
sock.sendto(b"ACK", addr) # 直接发回去,不需要建立连接
看到没?没有 listen,没有 accept,没有 connect。一个 recvfrom 收一个报文,一个 sendto 发一个报文。干净利落。
1.3 UDP 与 TCP 核心区别:一张表说清楚
我经常被问到:「老周,什么时候用 UDP,什么时候用 TCP?」我的回答是:看你能不能接受丢包。
| 对比维度 | UDP | TCP |
|---|---|---|
| 连接状态 | 无连接,发完就走 | 面向连接,三次握手 |
| 可靠性 | 尽力而为,不保证送达 | 确认重传,保证有序到达 |
| 头部开销 | 8 字节 | 20~60 字节 |
| 流量控制 | 无 | 滑动窗口 |
| 拥塞控制 | 无 | 慢启动、拥塞避免 |
| 报文边界 | 保留,一次 recv 一个完整报文 | 不保留,字节流需自行分包 |
| 适用场景 | 实时音视频、DNS、游戏、IoT | 网页、文件传输、邮件、数据库 |
💡 我的经验: 很多新手在写 UDP 应用时,会下意识地模仿 TCP 的「请求-应答」模式。但 UDP 没有拥塞控制,如果你在丢包率高的网络里疯狂重传,只会让网络更堵。我曾经见过一个 IoT 项目,设备每 100ms 发一次状态上报,结果在弱网环境下,重传风暴直接把基站打挂了。后来改成指数退避重传,问题才解决。
还有一个核心区别容易被忽略——报文边界。TCP 是流协议,你 send 两次 "Hello" 和 "World",对端 recv 一次可能收到 "HelloWorld",也可能收到 "Hel" + "loWorld"。UDP 不同,你 send 一次就是一个完整的报文,recv 一次收到的就是完整的数据报。这个特性在做协议设计时非常有用。
1.4 知识体系总览
下面这张图是我自己整理的 UDP 基础知识框架,你可以把它当作本章的「地图」:
这张图把 UDP 基础拆成了三个维度:报文结构告诉你「UDP 长什么样」,端口号告诉你「数据该给谁」,与 TCP 的对比告诉你「什么时候该用它」。后面的章节,我们会基于这张图一层层往下挖。