多个ThinkPHP站点共用同一Gateway集群时,必须共享唯一Register服务(如127.0.0.1:1236),所有站点GatewayClient配置统一指向该地址且加载同一autoloader;uid和群组名须加站点前缀隔离;Redis key需配置独立前缀(如tp1:);仅部署一套Gateway集群,BusinessWorker不写业务逻辑。

多个ThinkPHP站点怎么连同一个Gateway集群
必须让所有站点共用同一套 registerAddress,且不能各自启动 Register 进程。Register 是单点服务,只允许一个实例运行(比如 127.0.0.1:1236),否则 Gateway 之间无法同步连接状态。
每个 TP 站点的 GatewayClient 配置里都要显式指定这个地址:
GatewayClient::$registerAddress = '127.0.0.1:1236';
常见错误是各站点自己跑一套 start_register.php,结果注册中心分裂,sendToGroup 只能触达部分 Gateway,消息丢失无提示。
- 所有站点的
GatewayClient必须加载同一份 autoloader(推荐 vendor 统一管理,不要复制) - TP 的
bindUid调用必须传入全局唯一的$uid(建议带站点前缀,如tp1_admin_123) - 不同站点的群组名需加命名空间隔离,例如
tp1_room_general和tp2_room_general,避免sendToGroup误触其他站用户
Gateway进程如何区分不同站点的连接
Gateway 本身不识别“站点”,它只认 client_id 和绑定的 uid。区分站点的责任在业务层 —— 你得在 MVC 后端做路由判断。
例如用户 A 在 TP 站点 1 登录,调用 Gateway::bindUid($client_id, 'tp1_user_456');用户 B 在 TP 站点 2 登录,调用 Gateway::bindUid($client_id, 'tp2_user_789')。后续发消息时,Gateway::sendToUid('tp1_user_456') 就不会影响站点 2 的用户。
以 CLI 为先的表单构建器,采用 BYOK 理念。通过JSON Schema 生成美观的 HTML 表单,使用您自己的 SMTP 服务器处理提交,存储响应...
- 不能依赖
$_SERVER['HTTP_HOST']或 referer 做判断 —— WebSocket 握手不带这些字段 - 前端建立连接时,可在 URL query 中传站点标识:
ws://gateway.example.com?site=tp1,然后在onConnect回调里解析并存入$_SESSION(仅限 Gateway 进程内临时使用,不可跨进程) - 更稳妥的做法:在 bind 接口里由 TP 后端生成带站点上下文的
$uid,Gateway 只负责存储和转发
Redis 存储怎么避免多站点 key 冲突
GatewayWorker 默认用 Redis 存在线状态、分组成员等数据,但它的 key 命名没做多租户隔离。如果你让多个 TP 站点直连同一个 Redis DB,group:room_a 可能被站点 1 和站点 2 同时写入,造成混乱。
解决方案是强制 key 前缀化。修改每个站点的 config/gateway.php(或启动脚本中):
GatewayWorker\Lib\Gateway::$pidFile = '/tmp/gateway_tp1.pid'; GatewayWorker\Lib\Gateway::$redisHost = '127.0.0.1'; GatewayWorker\Lib\Gateway::$redisPort = 6379; GatewayWorker\Lib\Gateway::$redisDatabase = 0; // 关键:设置 Redis key 前缀 GatewayWorker\Lib\Gateway::$redisKeyPrefix = 'tp1:';
- 每个站点用独立的
$redisKeyPrefix,如tp2:、tp3: - 不要复用默认的空前缀,否则
group:xxx、uid:xxx全局可见 - 如果站点间需要有限互通(比如统一通知),应走额外的业务 Redis channel,而非共享 Gateway 的底层 key
为什么不能让多个站点共用同一套 Gateway 启动脚本
因为 start_gateway.php 会 fork 出固定数量的 Gateway 进程,每个进程绑定一个监听地址(如 websocket://0.0.0.0:8283)。多个站点若都执行它,会触发端口占用或 Register 地址冲突。
正确做法是:只部署一套 Gateway 集群(含 Gateway + BusinessWorker + Register),所有站点作为客户端接入。BusinessWorker 进程里不做任何站点逻辑,只做透传或轻量协议解析;真正的站点路由、权限、消息格式校验,全部下沉到各 TP 的 bind/send 接口里。
- Gateway 进程数、
startPort、lanIp等配置必须全局唯一,不能按站点复制一份再改端口 - BusinessWorker 的
onMessage回调里禁止写具体业务代码 —— 它只该做日志、心跳、连接保活等通用动作 - 最容易被忽略的一点:所有站点的
GatewayClient必须用相同版本,否则序列化协议不兼容,sendToGroup可能静默失败

















