onmessage不触发的主因是监听地址错误或协议不匹配;需绑定0.0.0.0、确认websocket/tcp协议类型一致、检查帧类型(text/binary)并确保客户端协议正确。

Workerman 或 Swoole 服务端 onMessage 不触发?先看监听地址是不是 0.0.0.0
很多情况根本不是代码问题,而是服务压根没收到包。Linux 内核对 127.0.0.1 监听地址有严格限制:只响应本机回环请求,外部 IP 发来的 SYN 包直接丢弃,onMessage 连执行机会都没有。
必须确认启动代码里 Worker 实例绑定的是 0.0.0.0:端口,不是 127.0.0.1:端口。改完不能 reload,得完整重启:php start.php stop && php start.php start。
验证是否生效:ss -tuln | grep :你的端口,输出中必须出现 *:端口 或 0.0.0.0:端口;如果还是 127.0.0.1:端口,说明配置没加载或被其他文件覆盖。
客户端发的是 TCP 还是 WebSocket?协议不匹配 onMessage 就是空转
onMessage 是协议层回调,不是万能入口。Swoole/Workerman 启动时指定的协议类型,决定了 onMessage 参数类型和触发条件:
- 启动
new Swoole\WebSocket\Server('0.0.0.0:9501')→onMessage参数是Swoole\WebSocket\Frame对象,只收 WebSocket 帧(且需握手成功) - 启动
new Swoole\Server('0.0.0.0:9501', SWOOLE_SOCK_TCP)→onReceive才是收裸 TCP 数据的入口,onMessage根本不会被调用 - 启动
new Worker('http://0.0.0.0:8080')→onMessage参数是Workerman\Protocols\Http\Request,不是原始数据
用 telnet 服务器IP 端口 直连测试最可靠:能收到回显,说明 TCP 层通;但 WebSocket 客户端连不上,大概率是没走 HTTP 升级流程或域名未配 WSS 白名单。
PHP 原生 socket 或自研 WebSocket 服务:没解帧就别指望 onMessage
WebSocket 协议规定,所有客户端发送的数据都带掩码、含帧头。Swoole 的 Swoole\WebSocket\Server 内部已自动完成解帧和掩码处理,所以你拿到的 $frame->data 是明文。
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
但如果你用 PHP 原生 socket_* 函数手写服务,或者在 Swoole 的 TCP Server 里硬解析 WebSocket 帧——那 socket_read() 或 $server->on('receive') 拿到的永远是原始字节流,不是 JSON 字符串。此时所谓 “onMessage 收不到消息”,其实是你压根没写解帧逻辑。
关键点:
- 检查是否误把
Swoole\Server当成Swoole\WebSocket\Server用 - 确认客户端 URL 是
wss://或ws://,不是tcp:// - 浏览器 DevTools 的
Network → WS → Frames里看 Type 列:如果是Text但服务端仍收不到,基本可断定是帧未解或协议栈错配
消息类型不匹配:前端 send ArrayBuffer,后端只接 String
这是静默失败最高发场景。前端调用 socket.send(new ArrayBuffer()) 发二进制帧,而 Swoole 的 onMessage 回调默认只处理文本帧($frame->opcode === WEBSOCKET_OPCODE_TEXT),二进制帧(WEBSOCKET_OPCODE_BINARY)会被忽略——不报错、不记录、不进回调。
解决方式只有两个:
- 前端统一发字符串:
socket.send(JSON.stringify({ ... })) - 后端显式判断帧类型:
public function onMessage($server, $frame) { if ($frame->opcode == WEBSOCKET_OPCODE_BINARY) { // 处理二进制数据,例如 new \Swoole\Coroutine\Http\Client 解析 return; } $data = $frame->data; // 此时才是字符串 }
注意:Swoole 默认不抛异常也不打日志,这种类型不匹配完全静默,必须靠 Frames 面板和 var_dump($frame) 确认 opcode 值。
真正卡住你的,往往不是“连不上”,而是“连上了,但协议没对齐、帧没解、地址没绑对”。调试时优先验证网络层和协议层,再查业务逻辑。










