ss -tuln 不显示 UDP 监听端口,需用 ss -unl 或 ss -tuln | grep udp;若无输出,检查 Workerman 是否启用 UDP Worker、协议是否为 udp://、回调是否为 onPacket 而非 onMessage。

ss -tuln 看不到 UDP 监听端口
UDP 是无连接协议,ss -tuln 查不到监听状态不等于没监听成功——它只显示 TCP 的 LISTEN 状态,UDP 用 ss -tuln | grep udp 或直接 ss -unl | grep :端口。若仍无输出,说明 Workerman 根本没启动 UDP Worker,或构造时协议写错了。
常见错误:new Worker('tcp://0.0.0.0:5678') 写成 tcp 却想收 UDP;正确写法必须是 new Worker('udp://0.0.0.0:5678')。注意:Workerman 的 UDP Worker 不支持 onMessage 回调,必须用 onPacket——写错回调名会导致收包静默失败,日志里也不会报错。
- 确认启动代码中协议为
udp://,不是tcp://、http://或拼写错误(如udb://) - 检查是否定义了
$worker->onPacket = function($connection, $data) { ... };,不是onMessage - UDP Worker 不会自动解析 HTTP 头或 WebSocket 握手,客户端发的必须是原始 UDP 数据报文
客户端发了数据,但 onPacket 完全不触发
这通常不是逻辑问题,而是网络层压根没把包送到 Workerman。UDP 比 TCP 更“脆弱”,没有连接状态,内核丢包不通知应用层。
先验证服务端是否真在接收:在服务器上用 tcpdump -i any udp port 5678 -w udp_test.pcap 抓包,再让客户端发一次。如果 tcpdump 能抓到包,说明网络通、防火墙放行、端口没被占;如果抓不到,问题出在路径上。
- 云服务器必须检查安全组:UDP 规则要显式添加,不能只开 TCP
- Linux 防火墙(如
firewalld)默认拦 UDP,执行sudo firewall-cmd --add-port=5678/udp --permanent && sudo firewall-cmd --reload - Docker 容器跑 Workerman 时,
-p 5678:5678/udp必须带/udp后缀,否则只映射 TCP - 客户端若用广播地址(如
192.168.1.255),服务端监听地址必须是0.0.0.0,且网卡需开启广播接收(多数默认开启)
onPacket 收到数据但内容异常或截断
UDP 数据报有最大传输单元(MTU)限制,以太网典型值为 1500 字节,IPv4 头 + UDP 头占 28 字节,实际 payload 最大约 1472 字节。超过就会被分片——而分片包在中间设备(如路由器、防火墙)容易被丢弃,且 Workerman 默认不重组。
常见现象:客户端发 2000 字节 JSON,$data 只有前 1472 字节,后半截消失;或干脆收不到整包。这不是 Workerman bug,是 UDP 协议特性。
- 强制客户端控制单包大小 ≤ 1400 字节(留余量),避免分片
- 不要在
onPacket里做耗时操作(如数据库写入),UDP 包是“来了就扔”,处理慢会导致后续包被内核丢弃(socket 接收缓冲区溢出) - 可用
socket_getopt($connection->getSocket(), SOL_SOCKET, SO_RCVBUF)查当前接收缓冲区大小,必要时在onWorkerStart中调大:socket_set_option($connection->getSocket(), SOL_SOCKET, SO_RCVBUF, 2*1024*1024)
Workerman UDP 和硬件设备联调总丢前几包
类似 STM32 开机 UDP 丢包问题,在 Workerman 侧虽不涉及 PHY 时序,但客户端(尤其是嵌入式)常在链路刚通时密集发包,而 Workerman UDP Worker 的 socket 接收缓冲区初始较小,或系统 UDP 队列积压未清,导致启动瞬间的包被内核丢弃。
这不是 Workerman 配置错误,而是 UDP 通信固有的“竞态窗口”。你看到的是 onPacket 没触发,其实包已被内核悄悄丢掉,连日志都留不下痕迹。
- 客户端发包前加 100–300ms 延迟,等网络栈稳定(对调试有效,量产需更健壮方案)
- 服务端启用
SO_REUSEADDR(Workerman 默认已开),避免重启时端口 TIME_WAIT 占用 - 关键业务别依赖 UDP 单包可靠,设计重传 + 序号机制,或改用 TCP+心跳保活
UDP 的“不可靠”是设计使然,不是故障。排查时永远优先确认:包是否真的抵达服务器网卡(tcpdump)、是否被内核接收(netstat -su 看 UdpInErrors)、是否进了 socket 缓冲区(ss -unli 看 rcvbuf 使用率)。绕过这些直接改 PHP 代码,大概率白忙。

















