CodeIgniter 无法直接实现 WebSocket,因其 HTTP 生命周期结束后 PHP 进程即销毁,onOpen/onMessage 等回调无法持续运行;必须用 Ratchet 或 Workerman 启独立服务,CI 仅负责页面渲染与消息存库,两者通过数据库或 Redis 共享状态。

onOpen、onMessage 等回调根本无法持续运行。
你看到的“连接成功”日志只是握手阶段的假象,几秒后必然断开,onMessage 永远不会触发——这不是配置问题,是架构限制。
为什么 CI 控制器里写 WebSocket 服务一定失败
WebSocket 握手虽用 HTTP GET + Upgrade: websocket 头发起,但后续帧通信完全脱离 PHP-FPM 或 Apache 的请求上下文。CI 的 Chat.php 控制器被 Nginx 调用一次后就退出,$conn->send() 所依赖的 ConnectionInterface 实例早已被回收。
- 你在浏览器控制台看到
WebSocket connection to 'ws://...' failed,通常是因为服务端进程已退出 - 用
php index.php chat start启动所谓“WebSocket 控制器”,实际只是执行完就结束,不是常驻进程 -
get_instance()在 Ratchet 进程中返回null,所有$this->db、$this->session都不可用
必须用 Ratchet 或 Workerman 启独立服务
Ratchet 是最常用选择,它不依赖 CI 引导,自己监听端口、维持连接、管理客户端列表。CI 只负责页面渲染、用户登录、消息存库;Ratchet 负责长连接、广播、在线状态同步。
- 安装:
composer require cboden/ratchet - 服务入口(如
chat_server.php)不能放在application/下,应与项目根目录平级,且不引入index.php - 数据库连接必须原生初始化:
$pdo = new PDO('mysql:host=localhost;dbname=chat', $user, $pass);,不能调用$this->load->database() - 用户身份绑定靠 token:CI 登录成功后写一条
ws_sessions记录(含user_id、token、expires_at);Ratchet 在onOpen()中解析 URL 参数?token=xxx查表绑定
CI 和 Ratchet 如何共享在线状态与消息
两者之间没有对象共享,只有数据共享。关键动作都落在数据库或 Redis 上,不能图省事去“复用模型”。
- 消息发送流程:前端 POST 到 CI 的
Messages::store()→ 存入messages表 → 触发 RedisPUBLISH chat:msg或轮询通知 Ratchet 进程 - 在线用户列表:Ratchet 每次
onOpen/onClose都更新ws_sessions表的last_active字段;CI 查这个表就能知道谁在线 - 广播逻辑在 Ratchet 里写:遍历
$this->clients,但只推送给目标用户或房间成员,别全量foreach—— 性能会随连接数线性下降 - 别用文件缓存存在线列表:并发写入易冲突;Redis 的
SET+EXPIRE更可靠
onMessage,而是设计好 CI 和 WebSocket 服务之间的边界。很多人卡在“怎么让 Ratchet 读到 CI 的 session 数据”,答案是:别读,重做一套轻量 token 绑定机制。一旦开始尝试在 Ratchet 里 require CI 的 autoloader 或调用 CI_Controller,基本就走进死胡同了。


















