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)
⚠ 避坑提醒: 我曾经在排查一个视频流卡顿问题时,抓包发现校验和全是 0。一开始以为是网卡 offload 导致,后来发现是中间防火墙把校验和字段改了。UDP 校验和虽然可选,但生产环境我建议你 永远不要关掉它。关掉校验和,数据损坏了你都不知道。

这里有个细节很多人忽略: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 报文结构 端口号与 Socket UDP vs TCP 对比 源端口 (16bit) 目的端口 (16bit) 长度 (16bit) 校验和 (16bit) 知名端口 0-1023 注册端口 1024-49151 动态端口 49152-65535 无连接 无重传 无拥塞控制 保留报文边界 核心要点:UDP 头部仅 8 字节,无连接、无状态、无可靠性保证 适合实时性要求高、能容忍少量丢包的场景

这张图把 UDP 基础拆成了三个维度:报文结构告诉你「UDP 长什么样」,端口号告诉你「数据该给谁」,与 TCP 的对比告诉你「什么时候该用它」。后面的章节,我们会基于这张图一层层往下挖。