GatewayWorker已封装连接路由、分组与广播等90%重复逻辑,而原生Workerman需手动维护连接映射、遍历client_id、处理离线重试与心跳,代码量增3倍且不支持分布式部署。

做聊天室,直接用 GatewayWorker,别自己在 Workerman 上从零搭连接路由、分组、广播——90% 的重复逻辑它已经封装好了。
为什么不能在 Workerman 里直接写 onMessage 发 send()?
因为 Workerman 的 $connection->send() 只发给当前 TCP 连接对象,而聊天室需要「把消息推给另一个用户」或「整个群」。你得自己维护所有在线连接的映射表、手动遍历 client_id、处理离线重试、同步心跳状态……稍有疏漏就会丢消息或卡死进程。
-
GatewayWorker把这事抽象成Gateway::sendToUid()和Gateway::sendToGroup(),底层自动查注册中心、转发到对应Gateway进程、再投递给真实客户端 - 你在
BusinessWorker的onMessage里调用这些方法时,完全不用知道对方连在哪台机器、用的是 WebSocket 还是 TCP - 如果硬用
Workerman实现类似逻辑,代码量翻 3 倍以上,且无法天然支持分布式部署
GatewayWorker 的三个进程不是主从关系,这点影响部署方式
新手常误以为 Register 是 master,Gateway 和 BusinessWorker 是 worker —— 实际上三者完全平级,靠长连接互相注册发现。这意味着:
-
Register进程只存Gateway地址(比如127.0.0.1:9600),不处理业务也不碰客户端 -
Gateway进程只做 IO:维持连接、转发数据、发心跳;崩溃了不影响业务逻辑执行 -
BusinessWorker才真正跑你的Events.php,但它只认$client_id和$gateway_client_id,根本不认识 HTTP session 或数据库 user 表 - 所以部署时可以分开:高带宽低 CPU 的机器跑
Gateway,高 CPU 的机器跑BusinessWorker,只要它们都能连上同一个Register
HTTP 接口和 WebSocket 不能混在一个端口,必须拆开
一个 PHP 进程没法同时高效处理 HTTP 短连接和 WebSocket 长连接。常见错误是想让 GatewayWorker 同时监听 80 端口提供网页和聊天服务——这不行。
- Web 页面、登录接口、消息历史等走传统 Web 框架(Laravel、ThinkPHP 或
Workerman单独起的HttpServer) - WebSocket 连接必须由
GatewayWorker的Gateway进程专门监听(例如ws://yourdomain.com:8282) - 前后端通信靠
GatewayClient:Web 后端调用Gateway::sendToUid()推送,而不是 echo 到 socket - UDP 场景不适用
GatewayWorker,必须退回原生Workerman写UdpConnection
真正容易被忽略的点是:绑定用户 ID 和 client_id 必须在前端建立 WebSocket 连接后立刻完成,否则后续 sendToUid 会找不到目标。这个动作不能延迟,也不能依赖 HTTP session,必须靠前端拿到 client_id 后主动 POST 到后端执行 Gateway::bindUid()。


















