php本身不支持原生websocket服务端,必须依赖cli常驻进程及第三方库(如workerman、ratchet、swoole);apache/nginx+php-fpm无法运行websocket服务,因不支持长连接与协议升级。

PHP 本身不支持原生 WebSocket 服务端,必须依赖常驻内存的 CLI 进程 + 第三方库或扩展。直接在 Apache/Nginx + PHP-FPM 下跑 WebSocket 服务是无效的——连接会立刻断开或卡在 pending 状态。
Workerman 启动后浏览器连不上 ws://,一直 pending
这不是代码写错了,而是 Workerman 默认监听 raw TCP,但浏览器发起的是 HTTP Upgrade 握手请求,服务端没响应 101 状态码就会卡住。
- 确认启动命令是
php start.php start(不是start -d后就不管了),控制台应输出Websocket worker starting - 客户端必须用
ws://localhost:6161(开发)或wss://yourdomain.com/wss(生产),绝不能用http://协议访问 - 若走 Nginx 反代,配置里缺一不可:
proxy_set_header Upgrade $http_upgrade和proxy_set_header Connection "upgrade" - 检查端口是否被占:
lsof -i :6161或netstat -tuln | grep 6161;残留进程会导致新代码不生效
onMessage 收到 $data 是 null、空字符串或乱码
Workerman 已自动解帧,$data 应该是 UTF-8 字符串。出现空值或乱码,基本是客户端发的数据格式不对,或服务端未正确处理编码。
- 前端发送前必须
JSON.stringify(),不要send({msg: 'hello'})直传对象 - 服务端接收后先判断:
if (is_string($data) && !empty($data)) { $msg = json_decode($data, true); } - 中文乱码大概率漏了
JSON_UNESCAPED_UNICODE:发送时用json_encode($msg, JSON_UNESCAPED_UNICODE) -
$connection->send()只接受string,传数组/对象会静默失败——无报错、无日志、无响应,是最常被忽略的坑 - 用 Apifox 或微信开发者工具测试时,注意它们默认发 raw 文本,不是 JSON,需手动切格式
广播消息只发给自己,或部分连接收不到
Workerman 的 $worker->connections 是所有 TCP 连接(含内部管理连接),不能直接遍历它来广播。WebSocket 连接需要显式维护容器,否则会调用失败或发给错误对象。
- 别写
foreach ($worker->connections as $conn) { $conn->send(); }——这会触发Call to a member function send() on null - 正确做法:用静态变量或全局数组存 WebSocket 连接,比如
static $clients = [];,在onConnect里$clients[$connection->id] = $connection;,断开时unset($clients[$connection->id]); - 更稳妥方案是上
GatewayWorker,它内置 UID 绑定和群组广播,避免手管连接生命周期 - 如果用 Swoole,记得开启心跳:
'heartbeat_check_interval' => 60, 'heartbeat_idle_time' => 600,否则断连连接不会自动清理,广播会发给已失效的 fd
Swoole vs Workerman:选哪个更稳
两者都能用,但定位不同:Swoole 是扩展级性能方案,Workerman 是纯 PHP 兼容性方案。别只看“谁更快”,要看你实际卡在哪。
- Swoole 要求安装 v4.8+ 扩展,
php -m | grep swoole必须有输出;它内置握手、帧解析、心跳,不用手撕协议,但对环境依赖强 - Workerman 不依赖扩展,PHP 7.4–8.4 全兼容,适合快速验证逻辑或部署受限环境,但广播、集群、平滑重启等需额外封装
- 如果你的服务器不能装扩展,或团队不熟悉 C 扩展运维,Workerman 是更少踩坑的选择;如果已有 Swoole 环境且追求高并发,优先用
swoole_websocket_server - 无论选哪个,都别把业务逻辑塞进 WebSocket 回调里——比如收到消息后直接查数据库、发邮件。应该把消息转给独立的 PHP-FPM 进程或消息队列(如 Redis pub/sub),让 WebSocket 服务只做连接管理和转发
最易被忽略的一点:WebSocket 服务和你的业务 PHP 应用是两个独立进程。它们之间没有共享内存,也没有自动通信通道。每次“推送”都要显式通过 HTTP API、Redis、文件或 Socket IPC 来通知对方——这点不厘清,后面所有实时功能都会变成玄学调试。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











