前期本人写过一篇关于 Swoole两种方案实现总后台给所有在线用户 群发通知
的文章, 现在研究了一种更好的实现案例。推荐生产环境使用该种方案
直接上案例:
use Swoole\Websocket\Server;
use Swoole\Coroutine as Co;
use Swoole\Runtime;
$server= new Server("0.0.0.0",20001);
/**
* 重点: 开启环境协程化,使所有的客户端协程话
*/
Runtime::enableCoroutine(SWOOLE_HOOK_ALL | SWOOLE_HOOK_CURL);
$server->set([
"worker_num"=>2,
"enable_coroutine"=>true,// 必须开启协程异步化
]);
$server->on("workerStart",function(Server $server,int $workerId){
$pid=$server->master_pid;
/**
* 在子协程中 实现的 redis 订阅端,是异步化的。 并不会影响客户端的连接
*/
if($workerId ==0){
Co::create(function()use($server){
$redis = new Redis();
$redis->connect("127.0.0.1");
$redis->setOption(Redis::OPT_READ_TIMEOUT,-1);
$redis->subscribe(['test'],function(Redis $instance,string $channelName,string $message)use($server){
/**
* 1. 遍历所有的连接,
* 2 . 判断所有的 ws客户端连接
* 3. 给客户端发送消息
*/
foreach ($server->connections as $fd){
if($server->isEstablished($fd)){
$server->push($fd,"send message to client success!");
}
}
});
});
}
// 这句话打印的次数与配置中worker_num 是一致的,表示上述redis订阅端并不会影响 worker进程接收请求
echo "进程{$workerId} 启动\n";
});
$server->on("request",function(\Swoole\Http\Request $request,\Swoole\Http\Response $response){
$response->status(201);
$response->header("content-type","text/html;charset=utf-8");
$response->end("哈哈".getmypid());
});
/**
* 接收客户端消息触发
*/
$server->on("message",function(Server $server, \Swoole\Websocket\Frame $frame){
$fd = $frame->fd;
$data = $frame->data;
echo "接收到客户端{$fd} 消息: {$data} \n";
});
$server->start();
网友评论