常见问题 - 向某个客户端发送数据
优质
小牛编辑
127浏览
2023-12-01
使用worker来做服务器,没有用GatewayWorker,如何实现向指定用户推送消息?
<?php
use WorkermanWorker;
require_once __DIR__ . '/Workerman/Autoloader.php';
// 初始化一个worker容器,监听1234端口
$worker = new Worker('websocket://workerman.net:1234');
// 进程数设置为1
$worker->count = 1;
// 新增加一个属性,用来保存uid到connection的映射(uid是用户id或者客户端唯一标识)
$worker->uidConnections = array();
// 当有客户端发来消息时执行的回调函数
$worker->onMessage = function($connection, $data)
{
global $worker;
// 判断当前客户端是否已经验证,即是否设置了uid
if(!isset($connection->uid))
{
// 没验证的话把第一个包当做uid(这里为了方便演示,没做真正的验证)
$connection->uid = $data;
/* 保存uid到connection的映射,这样可以方便的通过uid查找connection,
* 实现针对特定uid推送数据
*/
$worker->uidConnections[$connection->uid] = $connection;
return $connection->send('login success, your uid is ' . $connection->uid);
}
// 其它逻辑,针对某个uid发送 或者 全局广播
// 假设消息格式为 uid:message 时是对 uid 发送 message
// uid 为 all 时是全局广播
list($recv_uid, $message) = explode(':', $data);
// 全局广播
if($recv_uid == 'all')
{
broadcast($message);
}
// 给特定uid发送
else
{
sendMessageByUid($recv_uid, $message);
}
};
// 当有客户端连接断开时
$worker->onClose = function($connection)
{
global $worker;
if(isset($connection->uid))
{
// 连接断开时删除映射
unset($worker->uidConnections[$connection->uid]);
}
};
// 向所有验证的用户推送数据
function broadcast($message)
{
global $worker;
foreach($worker->uidConnections as $connection)
{
$connection->send($message);
}
}
// 针对uid推送数据
function sendMessageByUid($uid, $message)
{
global $worker;
if(isset($worker->uidConnections[$uid]))
{
$connection = $worker->uidConnections[$uid];
$connection->send($message);
}
}
// 运行所有的worker(其实当前只定义了一个)
Worker::runAll();
说明:
以上例子可以针对uid推送,虽然是单进程,但是支持个10W在线是没问题的。
注意这个例子只能单进程,要支持多进程或者服务器集群的话需要Channel组件完成进程间通讯,开发也非常简单,可以参考Channel组件集群推送例子一节。
如果希望在其它系统中推送消息给客户端,可以参考在其它项目中推送一节