UDP是为实时性优先场景设计的无连接、不可靠协议,适用于音视频通信、DNS查询、在线游戏、IoT数据上报及广播/多播等,关键在于容忍丢包且要求低延迟与确定性时延。

UDP 在 Linux 中不是“凑合用”的备选,而是为特定需求精心设计的协议。它不保证可靠、不维护连接、不排序、不重传,但正因如此,才在实时性压倒一切的场景中不可替代。
适合用 UDP 的典型场景
关键判断标准是:能否容忍少量丢包,是否极度依赖低延迟和确定性时延。
- 音视频实时通信:比如 VoIP 通话、视频会议。丢一两个语音包,人耳几乎听不出;但如果等重传,就会明显卡顿。UDP 的“发了就走”特性反而保障了流畅性。
- DNS 查询:域名解析通常只需一次请求+一次响应,报文极小(一般远小于 512 字节),且超时后客户端会自动重试。用 TCP 建连反而增加毫秒级开销。
- 在线游戏状态同步:玩家位置、动作等高频更新数据,旧状态很快失效。收到晚了不如不收,UDP 允许直接丢弃过期包,避免队头阻塞。
- 监控与传感器数据上报:IoT 设备周期性发送温度、电量等轻量指标,偶尔丢失不影响整体趋势判断,且设备资源有限,无法承担 TCP 的状态维护开销。
- 广播/多播应用:如局域网内服务发现(mDNS)、网络时间同步(NTP 的部分模式)。TCP 是点对点的,而 UDP 天然支持一对多传输。
开发时必须注意的硬性限制
UDP 行为由内核协议栈严格定义,绕不开底层约束,写代码前得心里有数。
- 单包最大 65507 字节:UDP 报头 8 字节 + IPv4 最大载荷 65527 字节(65535 − 20 字节 IP 头 − 8 字节 UDP 头)。超过此值,IP 层会分片,一旦任一片丢失,整包作废。实际建议控制在 1472 字节以内(以太网 MTU 1500 − IP 头 20 − UDP 头 8),避免链路层分片。
-
没有发送缓冲区:调用
sendto()后数据立即交给内核网络栈,不排队、不等待。这意味着:不能靠返回值判断对方是否收到;也不能指望系统帮你做流量整形或背压控制——应用层必须自行限速或加队列。 -
接收缓冲区会丢包:内核 UDP 接收队列满后,新到的数据包直接丢弃,不通知应用层。可通过
net.core.rmem_max调大上限,但治标不治本;更稳妥的做法是及时recvfrom(),避免积压。 -
严格的一对一收发模型:发 100 字节,就必须用一次
recvfrom()读完 100 字节。不能像 TCP 那样分多次读取。否则会触发EMSGSIZE错误或截断数据。
端口与进程绑定的实际规则
端口号不是文件句柄,绑定逻辑直接影响并发能力和权限管理。
-
一个端口只能被一个 socket 绑定:若进程 A 已 bind(8080),进程 B 再 bind(8080) 会失败(
EADDRINUSE)。这是五元组路由的基础——内核靠目的端口把包准确投递给唯一进程。 - 一个进程可 bind 多个端口:例如同时监听 UDP 53(DNS)和 67(DHCP),只需创建多个 socket 并分别 bind 即可。每个 socket 是独立通信端点。
-
0–1023 端口需 root 权限:普通用户进程无法 bind 知名端口。若需监听 53 端口,要么用
sudo启动,要么通过setcap 'cap_net_bind_service=+ep' ./your_app授予能力,而非提权整个进程。
应用层必须自己解决的问题
UDP 把自由留给上层,也把责任一并交出。常见问题没有银弹,全靠应用层设计补足。
- 丢包检测与重传:如 TFTP 协议在应用层实现 ACK 和超时重发;QUIC 则在用户态实现更复杂的可靠性机制。
- 数据分片与重组:要传大文件?先在应用层切块(每块 ≤1472 字节),加序号、校验和,再逐包发送;接收端缓存所有块,按序拼装,缺块则请求重传或放弃。
- 拥塞控制:Linux 内核不为 UDP 做速率调控。应用需实现类似 TCP 的慢启动、RTT 估测、丢包率反馈等逻辑,否则可能压垮网络。
- 连接概念模拟:虽无连接,但业务常需会话管理。可用四元组(源IP+源端口+目的IP+目的端口)作为会话 ID,在内存中维护状态,超时清理。


















