Workerman主动推送客户端收不到,根本原因是连接未建立或推送路径中断;需同步验证服务端是否真发出消息(如$worker->connections为空则客户端未连上)、网络链路是否通畅(如Nginx缺Upgrade头)、客户端是否正确监听message事件,缺一不可。

Workerman主动推送信息但客户端收不到,常见于连接未建立、路由错误、数据未真正发出或客户端未正确监听。排查必须从服务端推送逻辑、网络链路、客户端接收三端同步验证,不能只看某一边日志。
确认服务端是否真发出了消息
在推送代码执行位置加日志,用var_dump或Worker::log()输出发送前的连接对象和内容:
foreach ($worker->connections as $connection) { var_dump($connection->id, $connection->getRemoteIp(), '即将发送:hello'); $connection->send('hello'); }
如果var_dump没输出,说明循环根本没进——【$worker->connections为空,代表当前没有活跃连接】。此时不是推送失败,而是客户端压根没连上来。
检查$worker->onConnect回调是否被触发。没触发就说明WebSocket握手失败,重点查Nginx反向代理配置或浏览器控制台的WebSocket连接状态(status 101?还是400/404?)。
验证GatewayWorker模式下推送路径是否走通
方法一:用GatewayClient直连Register服务测试
在Web项目中写一个独立PHP脚本,require GatewayClient后填入真实Register地址:
Gateway::$registerAddress = '192.168.1.100:1236'; // 不能是0.0.0.0,必须是Register服务监听的IP+端口
执行Gateway::sendToAll('test from gatewayclient')。若客户端收到,说明GatewayWorker链路正常;若收不到,【检查start_register.php中$register->listen地址是否绑定到可访问IP,且防火墙放行1236端口】。
方法二:用GatewayWorker自带的sendToUid接口验证
在Events.php的onMessage里手动调用一次:
Gateway::sendToUid($client_id, 'uid测试消息');
注意:此操作要求客户端已通过Gateway::bindUid($client_id, $uid)完成绑定。没绑定就发不出去,且不会报错。
抓包确认数据是否到达客户端网卡
第一步:在服务端机器执行tcpdump -i any port 2346 -w workerman.pcap(替换为你实际监听的端口)
第二步:触发一次推送,等待10秒后Ctrl+C停止抓包
第三步:把workerman.pcap拖到本地用Wireshark打开,过滤tcp.port == 2346 and websocket
看到WebSocket: Text帧且Payload是你推送的内容,说明服务端已发出;没看到,说明推送逻辑根本没走到socket write层——可能是连接被close过但没清理引用,或$connection->send()返回false却没处理。
看到帧但客户端仍收不到,问题一定出在网络中间件(如Nginx WebSocket proxy_pass配置缺失Upgrade头)或客户端JS未监听message事件。
客户端侧强制验证接收能力
在浏览器控制台直接执行:
ws = new WebSocket('ws://your-domain.com:2346'); ws.onmessage = e => console.log('收到:', e.data); ws.onopen = () => ws.send('ping');
如果能收到服务端返回的pong或任何响应,证明链路通;如果onmessage从不触发,但onopen成功,说明服务端推送的数据格式非法(比如发了非UTF-8字符串、JSON没JSON.stringify、或WebSocket帧类型设为binary但客户端expect text)。
特别注意:Workerman默认发送的是text帧。若你用$connection->send("\x81\x05hello")手拼二进制帧,客户端JS会静默丢弃。

















