php 8.5.5 本身不支持 websocket,必须依赖 swoole 等扩展启动常驻 cli 进程;apache/nginx 下无法维持长连接,因 php 默认请求结束后进程销毁,无法处理 websocket 所需的持续 tcp 连接管理。

为什么 php -S 或 Apache 不能跑 WebSocket 服务
PHP 默认以 CGI/FPM 模式运行,每个请求结束后进程即销毁,无法维持 TCP 连接。WebSocket 要求服务端持续监听、响应 ping/pong、管理连接生命周期——这些都超出 PHP 标准运行时能力。
常见错误现象:Fatal error: Uncaught Error: Class 'Swoole\WebSocket\Server' not found(没装扩展)、Connection refused(误以为 php server.php 在浏览器里能直接访问 ws://)、WebSocket connection to 'ws://...' failed: Error during WebSocket handshake(Nginx 没配 Upgrade 和 Connection 头)。
Swoole 扩展必须显式启用且版本匹配
PHP 8.5.5 需搭配 Swoole ≥ v5.0.0(官方已明确支持 PHP 8.5),低于 v4.10 的版本可能触发 segfault 或协程异常。
安装后务必检查:php -m | grep swoole,并在 php.ini 中确认含 extension=swoole.so 且无分号注释。
关键配置项(非可选):
-
swoole.enable_coroutine=On(推荐开启,避免阻塞) -
swoole.display_errors=On(开发期必需,否则 silent fail) -
swoole.use_shortname=Off(防止命名冲突,尤其用 Laravel 等框架时)
'websocket' => ['enabled' => true] 必须写全键名,'websocket' => true 会被忽略。
服务启动必须脱离 Web 服务器独立运行
WebSocket 服务必须通过 CLI 启动并常驻:php start.php start -d(Workerman)或 php server.php(Swoole 原生写法)。任何试图用 file_get_contents('http://127.0.0.1:9502') 触发连接的逻辑,本质仍是 HTTP 请求,跟 WebSocket 无关。
典型结构:
- 监听地址不能写
127.0.0.1(外网无法访问),应为0.0.0.0:9502 -
on('message')回调中,$frame->data是原始字符串或二进制,JSON 解析前先is_string()判定 - 广播给所有人需遍历
$server->connections,但注意跳过当前连接 ID,避免回环 - 生产环境必须设
daemonize => true,但开发阶段建议daemonize => false,方便看var_dump和错误堆栈
Nginx 反向代理必须透传 Upgrade 协议头
前端访问 ws://your-domain.com/chat 实际走的是 HTTP 升级流程,Nginx 必须显式允许并透传协议升级请求,否则握手失败。
配置片段(放在对应 server 块内):
location /chat {<br> proxy_pass http://127.0.0.1:9502;<br> proxy_http_version 1.1;<br> proxy_set_header Upgrade $http_upgrade;<br> proxy_set_header Connection "upgrade";<br> proxy_set_header Host $host;<br>}
漏掉
proxy_http_version 1.1 或写成 1.0,会导致 Sec-WebSocket-Accept 头被丢弃;Connection 值必须是字符串 "upgrade",不是 upgrade(无引号会解析失败)。
真正卡住人的从来不是代码怎么写,而是搞不清「谁在管连接」——PHP 脚本只负责业务逻辑和消息通知,Swoole/Workerman 进程才是那个守着 TCP 连接、解帧、心跳、广播的实体。漏掉 daemonize、错配 Nginx 头、或者试图用 curl 直连 ws://,都是在混淆角色。php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











