必须用Workerman等常驻CLI进程实现PHP WebSocket服务,因PHP原生不支持;需显式使用websocket://协议、启动时输出Websocket worker starting、客户端用ws://访问、Nginx反代须透传Upgrade和Connection头、$data已解帧但需校验类型与编码、广播须维护独立连接容器而非遍历$worker->connections。

要让 PHP 服务端具备 WebSocket 即时通讯能力,必须绕过 HTTP 请求响应模型,建立持久化双向通道——Workerman 提供了开箱即用的 websocket:// 协议支持,但默认监听 raw TCP,不处理 HTTP Upgrade 握手,直接写 new Worker('websocket://0.0.0.0:2346') 却连不上,就是卡在这一步。
启动一个可连接的 WebSocket 服务
第一步:创建 Worker 实例时必须显式使用 websocket:// 协议前缀,不能用 tcp:// 或 http://;否则浏览器 ws:// 连接会一直 pending。
第二步:确保启动命令为 php start.php start(开发环境),且控制台输出包含 Websocket worker starting 字样;若只执行 php start.php start -d 后台运行,进程可能未真正加载 WebSocket 协议栈。
第三步:浏览器客户端必须用 ws:// 协议访问,例如 ws://localhost:2346;用 http:// 或 https:// 访问会触发 400 Bad Request 错误,因为服务器拒绝非 WebSocket 握手请求。
正确接收和解析客户端消息
方法一:在 onMessage 回调中先判断 $data 类型和内容有效性:
if (!is_string($data) || empty($data)) { return; } ——空值或 null 很可能是前端未 JSON.stringify() 就 send({}) 导致的非法帧,服务端无法解帧,$data 直接为 null。
方法二:对合法字符串执行 json_decode($data, true),但务必加 UTF-8 检查:if (mb_detect_encoding($data, 'UTF-8', true) === false) { return; },否则中文会变成乱码或 \uXXXX 序列。
方法三:发送响应前强制 JSON 编码并保留中文:$connection->send(json_encode(['code'=>0,'msg'=>'收到','data'=>$parsed], JSON_UNESCAPED_UNICODE));【$connection->send() 只接受 string,传数组会静默失败】
向所有在线用户广播消息
第一步:声明全局连接容器,在 onConnect 中注册连接:
$GLOBALS['clients'][$connection->id] = $connection;
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
第二步:在 onMessage 中遍历该容器,而非 $worker->connections:
foreach ($GLOBALS['clients'] as $client) { $client->send($broadcast_data); }
第三步:在 onClose 中及时清理:
unset($GLOBALS['clients'][$connection->id]);
注意:$worker->connections 包含内部管理连接(如 GatewayWorker 的 register 连接),直接遍历会导致 Call to a member function send() on null 错误。
Nginx 反向代理透传关键头字段
若前端域名与后端服务不在同一端口,必须配置 Nginx 透传 Upgrade 和 Connection 头,否则握手失败:
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
这两行缺一不可,漏掉任何一行都会使 WebSocket 连接降级为普通 HTTP,浏览器控制台报错:Error during WebSocket handshake: Unexpected response code: 200。

















