Workerman实现 WSS 基于客户端 ID 的精准推送核心思路是在服务端建立「客户端ID ↔ 连接实例」的映射关系推送时通过 ID 找到对应的连接再发送消息。下面结合 Workerman你当前使用的框架给出完整、可落地的实现方案1. 核心原理先理解逻辑客户端连接WSS服务端分配唯一connection_id客户端主动发送自定义ID服务端建立ID-connection映射需要精准推送根据自定义ID查映射表找到对应connection实例调用send方法推送消息关键是Workerman 每个连接自带唯一connection_id但这个 ID 是临时的断开重连会变所以需要绑定你业务侧的自定义客户端ID比如用户ID、设备ID。2. 完整实现代码Workerman 端以下是 GatewayWorker 架构下的核心代码适配你的 8282 端口 WSS 服务步骤1修改Events.php核心逻辑?php/** * GatewayWorker的事件处理类 */classEvents{// 存储「客户端ID → 连接connection」的映射全局数组publicstatic$client_map[];/** * 当客户端连接上来时触发 * param $connection 连接实例 */publicstaticfunctiononConnect($connection){// 1. 连接成功时Workerman自动生成唯一connection_id临时echo客户端连接成功临时ID{$connection-id}\n;}/** * 当客户端发送消息时触发核心绑定自定义ID * param $connection 连接实例 * param $data 客户端发送的消息JSON格式 */publicstaticfunctiononMessage($connection,$data){$datajson_decode($data,true);if(!$data){$connection-send(json_encode([code400,msg消息格式错误]));return;}// 场景1客户端绑定自定义ID比如用户IDif($data[type]bind){$client_id$data[client_id];// 客户端传的业务ID如用户ID 1001// ① 移除旧映射防止同一ID多端登录覆盖if(isset(self::$client_map[$client_id])){unset(self::$client_map[$client_id]);}// ② 绑定新映射自定义ID ↔ 连接实例self::$client_map[$client_id]$connection;// ③ 给connection绑定反向属性方便后续操作$connection-client_id$client_id;// 回复客户端绑定成功$connection-send(json_encode([code200,msgID绑定成功]));return;}// 场景2精准推送指令比如管理员后台触发if($data[type]push$data[target_id]$data[msg]){$target_id$data[target_id];// 要推送的目标客户端ID$msg$data[msg];// 推送的内容// ① 检查目标ID是否存在映射if(!isset(self::$client_map[$target_id])){$connection-send(json_encode([code404,msg目标客户端未连接]));return;}// ② 精准推送找到目标连接发送消息$target_connself::$client_map[$target_id];$target_conn-send(json_encode([typepush,from$connection-client_id??admin,msg$msg]));// ③ 回复推送方成功$connection-send(json_encode([code200,msg精准推送成功]));return;}// 其他消息处理...$connection-send(json_encode([code200,msg收到消息.$data[msg]]));}/** * 当客户端断开连接时触发清理映射避免内存泄漏 * param $connection 连接实例 */publicstaticfunctiononClose($connection){// 移除该连接对应的ID映射if(isset($connection-client_id)isset(self::$client_map[$connection-client_id])){unset(self::$client_map[$connection-client_id]);echo客户端{$connection-client_id}断开连接已清理映射\n;}echo临时ID{$connection-id}断开连接\n;}}步骤2客户端对接浏览器/JS 示例// 连接WSS服务用域名避免证书报错constwsnewWebSocket(wss://你的域名:8282);// 1. 连接成功后绑定自定义ID比如用户ID 1001ws.onopenfunction(){console.log(连接成功);// 发送绑定指令ws.send(JSON.stringify({type:bind,client_id:1001// 业务侧的唯一ID用户ID/设备ID}));};// 2. 接收服务端推送的消息ws.onmessagefunction(e){constresJSON.parse(e.data);console.log(收到消息,res);// 处理精准推送的消息if(res.typepush){alert(收到精准推送${res.msg});}};// 3. 主动触发精准推送比如给ID 1002推送消息functionpushToClient(){ws.send(JSON.stringify({type:push,target_id:1002,// 要推送的目标IDmsg:你好这是给你的精准推送}));}3. 进阶优化生产环境必做1映射表持久化/分布式上面的$client_map是内存数组仅适用于单服务器如果是多服务器集群需要用 Redis 存储映射关系// 绑定ID时存Redis$redisnewRedis();$redis-connect(127.0.0.1,6379);$redis-set(client:.$client_id,$connection-id);// 存connection_id$redis-set(connection:.$connection-id,$client_id);// 反向映射// 推送时查Redis$target_conn_id$redis-get(client:.$target_id);// 通过Gateway类获取对应连接Gateway::sendToClient($target_conn_id,$msg);2连接异常处理给映射表加过期时间避免无效连接残留推送前检查连接是否存活$connection-getStatus()。3GatewayWorker 专用方法如果用的是 GatewayWorker 完整架构推荐用官方封装的方法// 绑定IDGateway::bindUid($connection-id,$client_id);// 根据ID推送Gateway::sendToUid($client_id,$msg);// 解绑IDGateway::unbindUid($connection-id,$client_id);4. 测试验证步骤客户端A连接绑定ID1001客户端B连接绑定ID1002客户端A调用pushToClient()给1002推送消息客户端B能收到精准推送客户端A收到“推送成功”回复 → 验证完成。回顾精准推送的核心是建立「业务客户端ID ↔ Workerman连接实例」的映射关系客户端先主动绑定自定义ID服务端存储映射推送时通过ID查连接并发送消息单服务器用内存数组即可集群环境需用Redis存储映射结合GatewayWorker的sendToUid方法更高效断开连接时必须清理映射避免内存泄漏和无效推送。如果需要适配多服务器集群、或结合PHP后台非客户端触发实现服务端主动推送我可以补充对应的代码示例。
Workerman实现 WSS 基于客户端 ID 的精准推送
Workerman实现 WSS 基于客户端 ID 的精准推送核心思路是在服务端建立「客户端ID ↔ 连接实例」的映射关系推送时通过 ID 找到对应的连接再发送消息。下面结合 Workerman你当前使用的框架给出完整、可落地的实现方案1. 核心原理先理解逻辑客户端连接WSS服务端分配唯一connection_id客户端主动发送自定义ID服务端建立ID-connection映射需要精准推送根据自定义ID查映射表找到对应connection实例调用send方法推送消息关键是Workerman 每个连接自带唯一connection_id但这个 ID 是临时的断开重连会变所以需要绑定你业务侧的自定义客户端ID比如用户ID、设备ID。2. 完整实现代码Workerman 端以下是 GatewayWorker 架构下的核心代码适配你的 8282 端口 WSS 服务步骤1修改Events.php核心逻辑?php/** * GatewayWorker的事件处理类 */classEvents{// 存储「客户端ID → 连接connection」的映射全局数组publicstatic$client_map[];/** * 当客户端连接上来时触发 * param $connection 连接实例 */publicstaticfunctiononConnect($connection){// 1. 连接成功时Workerman自动生成唯一connection_id临时echo客户端连接成功临时ID{$connection-id}\n;}/** * 当客户端发送消息时触发核心绑定自定义ID * param $connection 连接实例 * param $data 客户端发送的消息JSON格式 */publicstaticfunctiononMessage($connection,$data){$datajson_decode($data,true);if(!$data){$connection-send(json_encode([code400,msg消息格式错误]));return;}// 场景1客户端绑定自定义ID比如用户IDif($data[type]bind){$client_id$data[client_id];// 客户端传的业务ID如用户ID 1001// ① 移除旧映射防止同一ID多端登录覆盖if(isset(self::$client_map[$client_id])){unset(self::$client_map[$client_id]);}// ② 绑定新映射自定义ID ↔ 连接实例self::$client_map[$client_id]$connection;// ③ 给connection绑定反向属性方便后续操作$connection-client_id$client_id;// 回复客户端绑定成功$connection-send(json_encode([code200,msgID绑定成功]));return;}// 场景2精准推送指令比如管理员后台触发if($data[type]push$data[target_id]$data[msg]){$target_id$data[target_id];// 要推送的目标客户端ID$msg$data[msg];// 推送的内容// ① 检查目标ID是否存在映射if(!isset(self::$client_map[$target_id])){$connection-send(json_encode([code404,msg目标客户端未连接]));return;}// ② 精准推送找到目标连接发送消息$target_connself::$client_map[$target_id];$target_conn-send(json_encode([typepush,from$connection-client_id??admin,msg$msg]));// ③ 回复推送方成功$connection-send(json_encode([code200,msg精准推送成功]));return;}// 其他消息处理...$connection-send(json_encode([code200,msg收到消息.$data[msg]]));}/** * 当客户端断开连接时触发清理映射避免内存泄漏 * param $connection 连接实例 */publicstaticfunctiononClose($connection){// 移除该连接对应的ID映射if(isset($connection-client_id)isset(self::$client_map[$connection-client_id])){unset(self::$client_map[$connection-client_id]);echo客户端{$connection-client_id}断开连接已清理映射\n;}echo临时ID{$connection-id}断开连接\n;}}步骤2客户端对接浏览器/JS 示例// 连接WSS服务用域名避免证书报错constwsnewWebSocket(wss://你的域名:8282);// 1. 连接成功后绑定自定义ID比如用户ID 1001ws.onopenfunction(){console.log(连接成功);// 发送绑定指令ws.send(JSON.stringify({type:bind,client_id:1001// 业务侧的唯一ID用户ID/设备ID}));};// 2. 接收服务端推送的消息ws.onmessagefunction(e){constresJSON.parse(e.data);console.log(收到消息,res);// 处理精准推送的消息if(res.typepush){alert(收到精准推送${res.msg});}};// 3. 主动触发精准推送比如给ID 1002推送消息functionpushToClient(){ws.send(JSON.stringify({type:push,target_id:1002,// 要推送的目标IDmsg:你好这是给你的精准推送}));}3. 进阶优化生产环境必做1映射表持久化/分布式上面的$client_map是内存数组仅适用于单服务器如果是多服务器集群需要用 Redis 存储映射关系// 绑定ID时存Redis$redisnewRedis();$redis-connect(127.0.0.1,6379);$redis-set(client:.$client_id,$connection-id);// 存connection_id$redis-set(connection:.$connection-id,$client_id);// 反向映射// 推送时查Redis$target_conn_id$redis-get(client:.$target_id);// 通过Gateway类获取对应连接Gateway::sendToClient($target_conn_id,$msg);2连接异常处理给映射表加过期时间避免无效连接残留推送前检查连接是否存活$connection-getStatus()。3GatewayWorker 专用方法如果用的是 GatewayWorker 完整架构推荐用官方封装的方法// 绑定IDGateway::bindUid($connection-id,$client_id);// 根据ID推送Gateway::sendToUid($client_id,$msg);// 解绑IDGateway::unbindUid($connection-id,$client_id);4. 测试验证步骤客户端A连接绑定ID1001客户端B连接绑定ID1002客户端A调用pushToClient()给1002推送消息客户端B能收到精准推送客户端A收到“推送成功”回复 → 验证完成。回顾精准推送的核心是建立「业务客户端ID ↔ Workerman连接实例」的映射关系客户端先主动绑定自定义ID服务端存储映射推送时通过ID查连接并发送消息单服务器用内存数组即可集群环境需用Redis存储映射结合GatewayWorker的sendToUid方法更高效断开连接时必须清理映射避免内存泄漏和无效推送。如果需要适配多服务器集群、或结合PHP后台非客户端触发实现服务端主动推送我可以补充对应的代码示例。