发布于2026-07-05 阅读(0)
扫一扫,手机访问
Swoole 的 UDP 服务器可不是你想象中那种“开箱即用”的玩意儿——底层无连接、无状态,参数写错一个,onPacket 直接哑火,sendto 出去了石沉大海。这些坑在面试现场几乎百发百中,不信你往下看。
SwooleServer 构造时必须传 SWOOLE_SOCK_UDPUDP 和 TCP 在 Swoole 内部走的是完全不同的两套事件分发路径。如果你图省事,随手写了 SWOOLE_SOCK_TCP,后果就是:onReceive 永远不触发,$server->getClientInfo() 返回 false,日志里连个错误提示都不给——静默失败最要命。
new SwooleServer('0.0.0.0', 9502, SWOOLE_PROCESS, SWOOLE_SOCK_UDP)SWOOLE_BASE 模式不支持 UDP,必须用 SWOOLE_PROCESS127.0.0.1 然后拿外网机器发包测试——本地回环和实际网卡行为完全是两码事,直接用 0.0.0.0 最省心onReceive 回调里的 $fd 不是连接 ID,而是对端 IP+端口的哈希值UDP 没有连接的概念,所以 $fd 在这里只是一个临时的标识符。每次收到不同客户端的数据,$fd 都可能变——拿它做缓存 key 或者绑定用户状态?想都别想。
$fd 只在当前 onReceive 调用中有效,别存到全局数组或 static 变量里指望复用$client_info['address'] 和 $client_info['port']ip:port 当 key 存到 Redis 或 Server::$connections 中$server->sendto() 回复时,目标地址必须和 onReceive 提供的一致UDP 的回复逻辑很简单:谁发来的就往谁那回。但很多人习惯性写成 $server->sendto($fd, $data)——大错特错。$fd 对 UDP 无效,sendto 必须带完整的地址信息。
$server->sendto($client_info['address'], $client_info['port'], $data)$client_info 或者写错字段名(比如写成 ip 而非 address),一样静默失败$client_info['address'] 返回的是带方括号的字符串(比如 [::1]),直接拼接端口会报错,需要先用 inet_pton 再 inet_ntop 处理iptables 和 SELinux,再检查 bind 权限UDP 包在进到 PHP 层之前,可能已经被系统拦截了。常见症状:netstat -uln | grep 9502 看不到监听,或者 tcpdump -i any udp port 9502 能抓到包但 PHP 不触发 onReceive。
setenforce 0firewalld 或 ufw 可能只放行了 TCP 却没开 UDP,确认规则里包含 udp --dport 9502真正容易被忽略的,是 UDP 数据报大小限制。内核默认 net.core.rmem_max 是 212992 字节,但应用层单次 recv 实际受 SO_RCVBUF 和 MTU 共同影响;超过 65507 字节的 UDP 包会被截断或丢弃,而 Swoole 不报错,只给你一个不完整的 $data——这种坑踩一次记一辈子。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8