需求背景
我需要在命令行中能比较简单的调取当前Websocket的在线数量
我这边在每个Websocket onOpen的时候使用swoole的table 做了一个fd的存储
碰到的问题和思路 Bridge的交互
在easyswoole的普通命令行中,是独立的临时进程,故拿不到主服务的内部数据
好在easyswoole有Bridge的桥接进程,提供给外部进程进行交互获取 主服务内部的数据
注册Bridge的Command
public static function mainServerCreate(EventRegister $register)
{
\EasySwoole\EasySwoole\Bridge\Bridge::getInstance()->getCommandContainer()->set(new BridgeWsCommand());
}
BridgeWsCommand.php
位于:App/Command/BridgeWsCommand.php (可根据自己项目调整)
<?php
namespace App\Command;
use App\Table\Fdtable;
use App\Table\UseridTable;
use EasySwoole\Bridge\Package;
use EasySwoole\EasySwoole\Bridge\AbstractCommand;
class BridgeWsCommand extends AbstractCommand
{
public function commandName(): string
{
return "websocket";
}
protected function count(Package $package, Package $response)
{
// 自己的业务逻辑
$data = Fdtable::getInstance()->getCount();
$response->setArgs($data);
}
}
自定义的Command
位于:App/Command/WebsocketCommand.php
<?php
namespace App\Command;
use App\Table\Fdtable;
use App\Table\UseridTable;
use EasySwoole\Bridge\Package;
use EasySwoole\Command\AbstractInterface\CommandHelpInterface;
use EasySwoole\Command\AbstractInterface\CommandInterface;
use EasySwoole\Command\CommandManager;
use EasySwoole\EasySwoole\Bridge\Bridge;
use EasySwoole\EasySwoole\Command\Utility;
use Swoole\Coroutine\Scheduler;
class WebsocketCommand implements CommandInterface
{
public function commandName(): string
{
// TODO: Implement commandName() method.
return "websocket";
}
public function exec(): ?string
{
// TODO: Implement exec() method.
$argv = CommandManager::getInstance()->getOriginArgv();
if (count($argv) < 3) {
echo "please input the action param!" . PHP_EOL;
return null;
}
// remove test
array_shift($argv);
// 获取 action 参数
$action = $argv[1];
// 下面就是对 自定义命令 的一些处理逻辑
if (!$action) {
echo "please input the action param!" . PHP_EOL;
return null;
}
// 获取 option 参数
$optionArr = $argv[2] ?? [];
switch ($action) {
case "count":
$run = new Scheduler();
$run->add(function () use (&$result) {
$result = Utility::bridgeCall($this->commandName(), function (Package $package) {
$data = $package->getArgs();
return $data;
}, 'count');
});
$run->start();
echo sprintf("当前websocket在线总数:%s" . PHP_EOL, $result);
break;
default:
echo "the action {$action} is not existed!" . PHP_EOL;
}
return null;
}
public function help(CommandHelpInterface $commandHelp): CommandHelpInterface
{
$commandHelp->addAction('count', '输出websocket的在线数量');
return $commandHelp;
}
public function desc(): string
{
return " 在线维护 websocket";
}
}
注册Command
修改Easyswoole 根目录下的bootstarp.php
<?php
//全局bootstrap事件
date_default_timezone_set('Asia/Shanghai');
EasySwoole\EasySwoole\Core::getInstance()->initialize();
\EasySwoole\Command\CommandManager::getInstance()->addCommand(new \App\Command\WebsocketCommand());
ps
目前我使用的easyswoole版本 3.4.4 当在bootstarp.php 中
EasySwoole\EasySwoole\Core::getInstance()->initialize();
注册了初始化 在使用默认的命令行 如 task、server、process 会出现初始化两次的情况,已反馈给官方人员
临时的处理方式:
/vendor/easyswoole/easyswoole/src/Command/DefaultCommand/*.php
下都有一个exec函数 函数内部有
Core::getInstance()->initialize();
将这个注释掉
(可做可不做,如没性能瓶颈的话无所谓,执行整个流程1s不到)
总结
如果需要在自定义命令行内获取主服务内部的数据,则需要和Bridge进程进行交互
Easyswoole底层已经帮我们写好了socket的交互,所以我们需要注册两个Command
1. Bridge的Command 获取内部数据的业务逻辑
2. 注册Easyswoole 命令行的Command 做与Bridge的数据交互获取,和控制台的窗口数据展示