UDP 实战与排错 — 抓包、设计与故障定位

UDP Wireshark 抓包、应用层重传/超时设计、udp 丢包/截断排查、与 TCP 对比 / 传输层 / RFC 768

这篇你能学到

  • 用 Wireshark / tcpdump 把 UDP 流量按端口、按包长挑出来,并识别分片黑洞的信号。
  • UDP 应用必须自己补上的东西(超时重传、序列号、ACK),以及查看监听端口、接收错误、调大缓冲的命令。
  • 六类常见故障(收端丢包、大包发不到、收不全、NAT 后无回包、端口不可达、数据"粘连")的结论先行式排查,外加对比表和面试速查。

1. 抓包观察

下面这些过滤式的作用:先把 UDP 流量整体捞出来或按端口聚焦,再重点盯住"接近 MTU 的大包"和"PMTUD 的 ICMP 回包"——UDP 的疑难杂症有相当一部分都出在包太大上。

过滤式作用
udp / ip.proto == 17所有 UDP
udp.port == 53指定端口(如 DNS)
udp.length > 1400接近/超过常见 MTU 的大包(易分片丢)
icmp.type == 3 && icmp.code == 4PMTUD,排查 UDP 分片黑洞

这两条命令:第一条带绝对时间戳实时看 DNS 流量,适合观察请求-响应的时间间隔;第二条把全部 UDP 完整落盘成 pcap,事后慢慢分析。

1
2
tcpdump -i eth0 -nn 'udp port 53' -tttt
tcpdump -i eth0 -nn 'udp' -s 0 -w /tmp/udp.pcap

Wireshark 中 Follow → UDP Stream 重组同组数据报;关注 Length、Checκsum status、是否分片(IP fragmentation)。

2. 常用设计 / 命令

这段内容做的事:前半部分是一个最小的 UDP echo 服务器骨架(绑定端口、循环 recvfrom 收一整条、原样加前缀回送),用来直观体会"一次收一条"的消息边界;后半部分是系统侧观测与调优——查看监听中的 UDP 端口、查看内核记录的 UDP 接收错误计数、以及调大接收缓冲上限防止收端丢包。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 应用层需自己补可靠:超时重传 + 序列号 + ACK
# Python 最小 echo 服务器骨架
python3 -c "import socket;s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM);s.bind(('0.0.0.0',1234));
print('listening');
import sys
while 1:
 d,a=s.recvfrom(4096);s.sendto(b'echo:'+d,a)"
# 内核/系统观测
ss -unlp # 监听的 UDP 端口
netstat -su | grep -i 'packet receive errors' # UDP 接收错误计数
sysctl -w net.core.rmem_max=26214400 # 增大 UDP 接收缓冲防丢

3. 常见故障与排错

现象:收端丢包

先记住结论: 包其实到了机器上,是在内核收到、应用没来得及取这一步被丢的——接收缓冲满了或应用处理太慢。

排查/解决:netstat -su 看 receive errors;增大 rmem_max;应用尽快消费。

现象:大包发不到

先记住结论: 小包能过大包不行,基本可以锁定 MTU 分片黑洞——DF 置位或中间设备把分片丢了。

排查/解决:把单 datagram 控制在 ≤1400B;必要时 dont-fragment 探测。

现象:偶尔收不全

先记住结论: 一条 datagram 被拆成多个分片,只要丢一片整条就废,所以表现为时好时坏。

排查/解决:应用层分片重传,或限制包长。

现象:NAT 后收不到回包

先记住结论: 不是对方没回,是 NAT 上那条映射表项已经超时被回收了——UDP 无连接,NAT 只能靠计时器猜。

排查/解决:缩短心跳间隔保 NAT 表项;用 STUN 打洞。

现象:端口不可达

先记住结论: 对端机器活着但那个端口上没有服务在听。

排查/解决:ICMP Port Unreachable;确认服务已起。

现象:数据"粘在一起"

先记住结论: 这锅不在 UDP——UDP 本身保留消息边界,是接收端读法不对或发送端自己把多条拼成了一条。

排查/解决:UDP 本身有边界,确认接收端按 datagram 读。

现象原因排查/解决
收端丢包接收缓冲满/处理慢netstat -su 看 receive errors;增大 rmem_max;应用尽快消费
大包发不到MTU 分片黑洞:DF 或中间丢分片把单 datagram 控制在 ≤1400B;必要时 dont-fragment 探测
偶尔收不全部分分片丢失整包失败应用层分片重传,或限制包长
NAT 后收不到回包无连接,NAT 表项超时缩短心跳间隔保 NAT 表项;用 STUN 打洞
端口不可达对端未监听ICMP Port Unreachable;确认服务已起
数据"粘在一起"误用流式 API / 自己拼包UDP 本身有边界,确认接收端按 datagram 读

4. 与其他协议对比

维度UDPTCPQUIC(over UDP)
连接有(在 UDP 上)
可靠是(自实现)
消息边界有(流内)
头部8B20+B8B + 自身帧
加密无(靠 TLS)内建
队头阻塞无(独立 datagram)流级隔离

5. 速查表 / 常见面试题

项目
RFC / IP 协议号RFC 768 / 17
头部长度8 字节
最大载荷65507 字节
校验和IPv4 可选,IPv6 必填
典型端口DNS 53 / DHCP 67,68 / SNMP 161
  • Q:UDP 为什么"不粘包"? 它是 datagram 模型,每 recvfrom 收到完整一条,边界由协议保留。
  • Q:UDP 不可靠,为何 DNS 用它? DNS 多为单请求单响应,UDP 省握手;超时未达应用层重试,简单高效。关键事务可切 TCP(RFC 7766)。
  • Q:UDP 没有拥塞控制危险吗? 是。无节制 UDP 会压垮网络,故现代协议(QUIC)在 UDP 之上自建拥塞控制。
  • Q:为什么 UDP 最大 65507 字节? 长度字段 16 bit 最大 65535,减 IP(20)+UDP(8)=65507。
  • Q:UDP 能广播/组播吗? 能,无连接特性使其天然支持一对多投递。