Computer NetworkNotes

第 07 章:UDP

zjc 于 2026-01-07 发布

这是《计算机网络 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开,代码块保留了原书可直接运行的版本。 UDP 是无连接、不可靠、面向数据报的传输协议。它没有连接建立、重传、排序、流量控制和拥塞控制,因此代价小、延迟低,但也把可靠性问题交给了应用层。DNS、NTP、视频通话、游戏和 QUIC 都运行在 UDP 上。

7.1 UDP 头部

UDP 头部只有 8 字节:

| Source Port | Destination Port |
| Length      | Checksum         |

与 TCP 相比:

维度 TCP UDP
连接
可靠 重传确认 尽力而为
顺序 字节流有序 数据报可能乱序
流控 滑动窗口
拥塞控制
头部 至少 20 字节 8 字节
边界 字节流 保留数据报边界

UDP 保留消息边界。发送两次数据报,接收方通常按两次读取;TCP 则是连续字节流,需要应用协议划分消息。

7.2 UDP 适用场景

适合:

  1. 实时音视频,宁可丢帧也不愿等待重传;
  2. 游戏同步,低延迟优先;
  3. DNS 查询,一问一答;
  4. 广播或多播;
  5. 内网服务发现;
  6. 作为 QUIC 的底层承载;
  7. 高频遥测,允许少量丢失。

不适合:

  1. 转账、下单等强一致业务;
  2. 大文件可靠传输;
  3. 需要严格顺序且不可丢的日志;
  4. 未经治理的公网大规模服务;
  5. 没有应用层确认与限流的请求响应。

7.3 使用 UDP 的代价

UDP 简化了协议,但复杂度不会消失,而是转移到应用层:

问题 应用层方案
丢包 序号、ACK、重传或 FEC
乱序 序号重组
重复 去重
流控 接收窗口或速率限制
拥塞控制 自定义 CC 或基于带宽探测
身份安全 DTLS 或自定义加密
连接管理 会话 ID、心跳、超时

QUIC 正是这种思路:基于 UDP,在用户态实现可靠流、多路复用、加密和现代拥塞控制。

7.4 Linux UDP 缓冲区

UDP 没有发送缓冲的重传语义,但内核仍需要队列。

查看:

sysctl net.core.rmem_max
sysctl net.core.wmem_max
sysctl net.core.rmem_default
sysctl net.core.wmem_default

查看统计:

ss -lun
netstat -su

关注:

  1. RcvbufErrors:接收缓冲不足;
  2. SndbufErrors:发送缓冲不足;
  3. InErrors:校验和等错误;
  4. InDatagrams / OutDatagrams
  5. receive errors 增长。

如果 UDP 接收方处理慢,包会被直接丢弃,不会像 TCP 一样通过窗口通知发送方减速。

7.5 UDP 编程示例

服务端:

import socket

server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server.bind(("0.0.0.0", 9000))

while True:
    data, addr = server.recvfrom(4096)
    server.sendto(b"ack:" + data, addr)

客户端:

import socket

client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
client.settimeout(2)

for i in range(3):
    client.sendto(f"ping-{i}".encode(), ("127.0.0.1", 9000))
    try:
        data, _ = client.recvfrom(4096)
        print(data.decode())
    except socket.timeout:
        print("timeout")

如果没有超时,一次丢包就可能让客户端永久等待。

7.6 NAT 与 UDP

UDP 无连接,NAT 映射通常依赖超时维护:

内网主机发送 UDP
  -> NAT 创建五元组映射
     -> 空闲超时后删除
        -> 对端再发送无法进入

应用层常见方案:

  1. 心跳保活;
  2. STUN 获取公网映射;
  3. TURN 中继;
  4. ICE 收集候选地址;
  5. 连接迁移时使用会话标识。

QUIC 使用 Connection ID 帮助在地址变化后恢复连接,但路径和 NAT 仍需正确处理。

7.7 UDP 排障

# 查看监听
ss -lunp

# 测试连通性
nc -u -v 10.20.1.10 9000

# 抓包
tcpdump -i eth0 udp port 9000 -nn

# 统计
netstat -su

排障要点:

  1. 双端是否都使用 UDP;
  2. 是否单向可达;
  3. 安全组是否放行;
  4. 接收队列是否溢出;
  5. 应用是否阻塞;
  6. 数据报是否超过路径 MTU;
  7. NAT 映射是否超时;
  8. 是否存在丢包和乱序。

本章小结

UDP 提供低开销、无连接的数据报传输,保留消息边界,但不提供可靠、有序、流控和拥塞控制。实时音视频、DNS、游戏和 QUIC 适合 UDP,而关键业务必须由应用层补足可靠性。UDP 排障要关注接收缓冲丢弃、单向可达、NAT 超时和路径 MTU。

思考题

  1. TCP 和 UDP 对消息边界的处理有什么不同?
  2. 为什么实时视频可以接受少量丢包?
  3. UDP 接收方处理慢会发生什么?
  4. QUIC 为什么基于 UDP 而不是直接修改 TCP?
  5. 设计一个可靠的 UDP 协议需要哪些字段和机制?