onMessage不触发主因是连接未进入监听队列:监听地址需为0.0.0.0而非127.0.0.1,端口须开放且客户端协议匹配WebSocket;$data类型取决于发送方式,解析需判空、验UTF-8、加JSON_UNESCAPED_UNICODE。

Workerman 的 onMessage 不是“自动解析消息”的魔法函数,它只负责把原始字节流或 WebSocket 帧内容原样传给你——能不能收到、收到什么、怎么用,全取决于协议匹配、网络暴露、数据格式这三关是否打通。
为什么 onMessage 根本不触发?
不是代码写错了,而是连接压根没进 Workerman 的监听队列。
- 监听地址写成
127.0.0.1:2346:外部设备(包括同局域网手机、浏览器)发包会被 Linux 内核直接丢弃,onMessage连影子都见不到;必须改成websocket://0.0.0.0:2346并执行完整重启:php start.php stop && php start.php start - 端口被防火墙/云服务器安全组拦截:用
ss -tuln | grep :2346确认看到的是*:2346或0.0.0.0:2346,而不是127.0.0.1:2346 - 客户端协议和 Worker 协议不一致:比如 Worker 启的是
websocket://,但前端用new WebSocket('http://...')或后端硬件模块(如 ESP32)直连 TCP 端口——WebSocket 握手失败会秒断,onMessage永远不会被调用
onMessage 收到的 $data 是什么类型?
WebSocket 协议本身不规定 payload 格式,$data 可能是字符串、二进制帧,甚至 null —— 全看客户端怎么发、Workerman 怎么解帧。
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
- 前端用
ws.send("hello"):$data 是 string,可直接json_decode($data, true) - 前端没
JSON.stringify()就 send({}):$data 很可能是null,因为非法帧无法解码,需加判空:if (!is_string($data) || empty($data)) { return; } - 前端发送 ArrayBuffer(如压缩数据、Protobuf):$data 是
Workerman\Connection\TcpConnection对象的二进制帧,需手动处理$connection->recv()或改用Worker::setProtocol()注册自定义协议 - 中文乱码:不是编码问题,是没做 UTF-8 检测,
mb_detect_encoding($data, 'UTF-8', true) === false时应拒绝解析,否则json_encode会输出\uXXXX序列
如何安全地解析和响应?
$connection->send() 只接受 string 类型,传数组会静默失败,且不处理字符编码。
- 强制保留中文:响应时必须加
JSON_UNESCAPED_UNICODE标志,例如:$connection->send(json_encode(['code'=>0,'msg'=>'收到'], JSON_UNESCAPED_UNICODE)); - 避免 JSON 解析崩溃:在
onMessage中对$data做try/catch包裹,防止非法 JSON 导致整个连接中断 - 广播前检查连接状态:遍历
$connection->worker->connections时,需先判断$client_connection->isConnected(),否则向已断开连接发消息会抛出异常 - 不要在
onMessage里做耗时操作(如 DB 查询、远程 HTTP 请求):会阻塞当前进程,影响其他连接;应投递到异步任务或消息队列
最常被忽略的一点:Workerman 的 onMessage 是同步回调,它不帮你做协议协商、不校验 JSON 结构、不重试丢失帧、也不管理连接生命周期。你得自己守住边界——从网络层暴露、到帧格式识别、再到业务逻辑分发,每一步都得亲手确认。否则看似“连上了”,其实只是握手成功,消息早就在半路被过滤或丢弃了。

















