PHP原生不支持长连接,必须依赖Swoole等常驻进程扩展;FPM模式下无法维持socket连接,WebSocket服务只能在CLI模式下通过事件循环长期驻留运行。
PHP 原生不支持长连接,必须依赖 Swoole 这类常驻进程扩展才能真正跑起 WebSocket 服务;FPM 模式下任何“WebSocket”方案都是伪实时,本质仍是轮询或 Server-Sent Events(SSE)。
为什么不能直接在 Laravel/Symfony 的 FPM 上启 WebSocket 服务
因为 PHP-FPM 是请求-响应生命周期模型:每个 HTTP 请求处理完就释放所有资源,无法维持 socket 连接。哪怕你用
手动建连接,进程一结束,连接就断。
必须运行在 CLI 模式下,靠事件循环长期驻留内存
Laravel 的
或 Nginx + PHP-FPM 组合,压根没有「监听端口 + 管理连接」的能力
所谓“集成”,实际是两个独立进程:FPM 处理业务逻辑(如登录、消息存库),Swoole 进程单独跑 WebSocket 服务,二者靠
或
通信
Swoole WebSocket 服务启动时的常见报错与修复
最典型的是
,说明端口被占;或者
,多因 Swoole 版本与 PHP 不兼容。
检查端口占用:
或
,杀掉残留进程
Swoole 安装后务必验证:
,确认
PHP 8.2+ 用户注意:Swoole 5.0.3 之前版本存在协程调度 bug,建议升到
别在
回调里直接调
或
—— 会阻塞整个 event loop,改用
如何让客户端稳定重连而不压垮服务端
前端用原生
API 时,
触发后立刻
是最危险的做法,容易引发雪崩。
PHP 8.5.5
PHP 8.5.5 是 PHP 8.5 分支的维护更新版本。该版本延续了“小步快跑”的迭代逻辑,通过深度错误修复、底层性能微调以及安全加固,旨在为开发者提供一个更健壮、更高效的运行环境。该版本严格遵守语义化版本规范,不包含破坏性变更。
下载
立即学习
“
PHP免费学习笔记(深入)
”;
必须实现指数退避:
,而非固定间隔
重连前加随机抖动(±300ms),避免集群内大量客户端同步重试
服务端配合做连接频控:在
中查 Redis 记录该 IP 5 分钟内连接次数,超限则
心跳不能只靠浏览器自动 ping/pong —— 客户端需主动发
,服务端在
中识别并回
,超时未收到则
广播消息性能瓶颈在哪,怎么绕过
直接遍历
并逐个
,在万级连接时 CPU 和网络 IO 都会打满。
不要用
广播 —— connections 是迭代器,每次遍历都触发全量扫描
改用
把广播任务投递到 task 进程,由它异步分片推送(例如每批 200 个 fd)
更优解是用 Redis Pub/Sub:客户端发消息 → 写 Redis Channel → Swoole 的
监听 → 收到后只推给目标用户(非全网)
如果必须全网广播,启用
(Swoole 5.0+),对文本消息自动 gzip
真正的难点不在写通连接,而在于连接数上去之后,内存泄漏、协程上下文污染、Redis 连接池耗尽这些隐性问题才会暴露——建议上线前用
或
模拟 5000+ 连接持续 30 分钟,观察
和
输出。
socket_createSwoole\WebSocket\Serverphp artisan serveRedis pub/subUnix socketFailed to listen on port: 9501, Error: Address already in useSegmentation faultlsof -i :9501netstat -tuln | grep 9501php --ri swoolewebsocket => enabled5.1.0+onMessagefile_get_contentscurl_execSwoole\Coroutine\Http\ClientWebSocketonclosenew WebSocket()1s → 3s → 7s → 15sonOpen$fd->close(){"type":"ping"}onMessage{"type":"pong"}$server->close($fd)$server->connectionspushforeach ($server->connections as $fd)$server->task()Redis->subscribe()websocket.compress = Onabwrkmemory_get_usage()swoole_server->stats()