workerman 5.2.3 是稳定版,开发聊天室需聚焦协议选型、连接管理、消息路由与状态维护;它以常驻进程运行 websocket 服务,不依赖 nginx+php-fpm,适合实时双向通信。

Workerman 5.2.3 是当前稳定且广泛使用的版本,开发聊天室项目关键在于协议选型、连接管理、消息路由和状态维护。它不依赖传统 Web 服务器(如 Nginx+PHP-FPM),而是以常驻进程方式运行 WebSocket 服务,适合实时双向通信。
一、环境准备与基础服务启动
确保 PHP 版本 ≥ 7.4(推荐 8.1+),已安装 Composer,并关闭 SELinux 或防火墙对目标端口(如 8080)的拦截。
- 新建项目目录,执行:
composer require workerman/workerman:5.2.3 - 创建 chat.php,初始化 WebSocket Worker:
use Workerman\Worker;
$ws_worker = new Worker('websocket://0.0.0.0:8080');
$ws_worker->count = 2; // 根据 CPU 核数设置
// 存储在线用户:$connection->id => ['name' => '张三', 'ip' => '192.168.1.100']
$ws_worker->connections_map = [];
$ws_worker->onConnect = function ($connection) {
$connection->is_login = false;
};
$ws_worker->onMessage = function ($connection, $data) use ($ws_worker) {
// 后续处理登录、发消息、广播等逻辑
};
$ws_worker->onClose = function ($connection) use ($ws_worker) {
// 从 $ws_worker->connections_map 中移除该连接
};
Worker::runAll();
二、实现用户登录与身份绑定
聊天室必须区分用户,不能仅靠连接对象。建议用唯一标识(如随机 token 或前端传入昵称 + 时间戳拼接)避免重名冲突,服务端需校验并绑定到 connection 实例。
- 客户端首次发送 JSON 消息:
{"type":"login","name":"小明"} - 服务端 onMessage 中解析:
→ 检查 type 是否为 login;
→ name 长度、非法字符过滤(正则 /^[a-zA-Z0-9\u4e00-\u9fa5_]{2,12}$/);
→ 若未登录且昵称未被占用,存入 $ws_worker->connections_map[$connection->id] = ['name'=>'小明', 'login_time'=>time()];
→ 设置 $connection->is_login = true,并返回 {"status":"ok","msg":"登录成功"}。 - 后续所有消息都需先判断 $connection->is_login,否则拒绝处理。
三、支持广播与单聊的消息分发逻辑
消息体建议统一格式,例如:
{"type":"chat","to":"全体"|"小红","content":"你好!"}
- 广播(to 为 "全体" 或空):遍历 $ws_worker->connections,跳过自己,向每个已登录连接 send() 该消息(含 sender 名);
- 单聊(to 为指定昵称):遍历 $ws_worker->connections_map 查找匹配 name 的 connection_id,再通过 $ws_worker->connections[$id]->send() 推送;
- 服务端不保存历史消息,如需持久化,应在 onMessage 中插入 MySQL 或 Redis(例如用 redis->lPush("chat:history", json_encode($msg)))。
四、前端连接与基础交互示例
浏览器中使用原生 WebSocket 连接,注意跨域问题已在服务端由 Workerman 自动处理(WebSocket 协议本身无同源限制,但握手请求受浏览器策略影响,实际开发中建议反向代理或确保域名一致)。
- 建立连接:
const ws = new WebSocket('ws://your-domain.com:8080'); - 登录:
ws.send(JSON.stringify({type:'login', name:'李四'})); - 监听消息:
ws.onmessage = e => { const msg = JSON.parse(e.data); console.log(msg); }; - 发送聊天:
ws.send(JSON.stringify({type:'chat', to:'全体', content:'今天天气不错'}));
不复杂但容易忽略:务必在 onClose 和 onError 中清理 connections_map,否则内存泄漏会导致连接数虚高、新用户无法登录。











