SkillAgentSearch skills...

MiniSwoole

Mini Swoole for TCP, UDP, HTTP, Websocket framework based on Swoole

Install / Use

/learn @xwmhmily/MiniSwoole
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Mini Swoole

Write Less and Do More

 __  __ _       _   ____                     _      
|  \/  (_)_ __ (_) / ___|_      _____   ___ | | ___ 
| |\/| | | '_ \| | \___ \ \ /\ / / _ \ / _ \| |/ _ \
| |  | | | | | | |  ___) \ V  V / (_) | (_) | |  __/
|_|  |_|_|_| |_|_| |____/ \_/\_/ \___/ \___/|_|\___|
<hr />
  • 支持 TCP, UDP, HTTP, Websocket <br />
  • Master-Worker 模式<br />
  • Module-Controller-Model 分层 <br />
  • MySQL 断线自动重连 <br />
  • Timer, Task 简易封装 <br />
  • MySQL, Redis 连接池<br />
  • MySQL 分表分库 <br />
  • JSON 作数据通信格式<br />
  • Shell 脚本控制服务<br />
  • Autoload<br />
  • 安全过滤<br />
  • 日志收集<br />
  • 心跳检测<br />
  • 自动路由<br />
  • 多模块划分
  • 中间件与插件
  • Process 管理
<hr />

环境要求

  • PHP >= 7.0 <br />
  • swoole, 建议 2.2.0 <br />
  • pdo <br />
  • redis <br />
  • pdo_mysql <br />
<hr />

安装

  • Git clone 至任一目录
  • 创建数据库并导入SQL 文件
<hr />

配置

  • EVN 的定义在 Boostrap.php 的第一句, 请升级脚本(deploy.py)自行根据环境修改<br />
  • 配置文件是 conf/ENV.php。 ENV 区分为 DEV, UAT, PRODUCTION, 请自行根据运行环境调整 <br />
  • common 为公共配置部分, 影响整体 <br />
  • 七个 $section 分为: common, http, tcp, udp, websocket, mysql, redis 配置 <br />
  • 配置文件的 key 务必使用小写字母 <br />
  • 任意地方均可使用 Config::get($section) 来获取配置文件中 $section 的参数
  • 任意地方均可使用 Config::get($section, $key) 来获取配置文件中 $section 中的 $key 对应的参数
<hr />

CLI 命令

  • 启动: sh shell/socket.sh start <br />
  • 状态: sh shell/socket.sh status <br />
  • 停止: sh shell/socket.sh stop <br />
  • 重启: sh shell/socket.sh restart <br />
  • Reload: sh shell/socket.sh reload, 重启所有Worker/Task进程 <br />
<hr />

心跳检测

  • 利用Crond 定时运行 shell/socket.sh heartbeat 即可<br />
<hr />

使用

  • 采用 Module-Controll-Model 模式, 所有的请求均转至 Module-Controller下处理 <br />
  • 默认 Module 为index, 无须声明, 对应的控制器文件位是根目录的 controller<br />
  • 在配置文件的 module 中声明新模块,以英文逗号分隔,如 'Api, Admin, Mall, Shop', 对应的控制器文件是 /module/$moduleName/controller<br />
  • 中间件:很多时候,我们需要在请求前与后做一些前置与后置的统一业务,比如授权认证,日志与流量收集,中件间就派上用场了。
<hr />

日志和错误处理

  • 系统的错误文件由 $config['common']['log_file'] 指定<br />
  • $config['common']['error_level'] 指定手动记录日志的级别, [1|2|3|4|5], 分别代表 DEBUG, INFO, WARN, ERROR, FATAL,低于规定的日志级别则不记录 <br />
  • $config['common']['error_file'] 指定手动记录日志的文件<br />
  • 任意地方调用 Logger::debug($msg); Logger::info($msg); Logger::warn($msg); Logger::error($msg); Logger::fatal($msg); 则将 $msg 以指定的级别写入 $config['common']['error_file']<br />
  • SQL 的错误文件由 $config['common']['mysql_log_file'] 指定, 当执行SQL发生错误时,自动写入, 级别均为 ERROR<br />
public function log(){
    try{
        Logger::debug('This is a debug msg');
        Logger::info('This is an info msg');
        Logger::warn('This is a warn msg');
        Logger::error('This is an error msg');
        Logger::fatal('This is a fatal msg');
        Logger::log('This is a log msg');

        $level = Config::get('common', 'error_level');
        $this->response->write('Current error_level => '.$level);
    }catch (Throwable $e){
        $this->error($e);
    }
}
  • log_method 指定保存日志的方式,默认是 file, 可选 redis. 若选择 redis, 则配置多一个 redis_log, 好处是啥?直接对接至 ELK !
    'redis_log' => [
        'db'    => '0',
        'host'  => '192.168.1.50',
        'port'  => 6379,
        'pwd'   => '123456',
        'queue' => 'Queue_log',
    ],
  • 为了避免由于exception, error 导致worker 退出后客户端一直收不回复的问题, 控制器中使用 try...catch(Throwable) 来处理
// 故意令 $this->m_player 为空
public function onError(){
    try{
        $result = $this->m_player->SelectOne();
        $this->response->write('Result is => '.$result);
    }catch (Throwable $e){
        $this->error($e);
    }
}

调用此方法,客户端将以 TAB 显示错误提示, 包括 General Eroor, Trace info, GET, POST, COOKIE, SERVER 的数据,如果是 SQL 报错,还将显示报错的 SQL 语句,给于 debug 最大的便利

<hr />

TCP 服务

  • 将 tcp 段的enable 设置为 true, 其他服务设置为 false <br />
  • sh shell/socket.sh restart 重启服务 <br />
  • ps -ef | grep Mini 将看到

    Mini_Swoole_tcp_master: 为 master 进程 <br /> Mini_Swoole_manager: 为 manager 进程<br /> Mini_Swoole_task: N 个 task 进程 <br /> Mini_Swoole_worker: M 个 worker 进程 <br />

<hr />

UDP 服务

  • 将 udp 段的enable 设置为 true, 其他服务设置为 false <br />
  • sh shell/socket.sh restart 重启服务 <br />
  • ps -ef | grep Mini 将看到 <br />

    Mini_Swoole_udp_master: 为 master 进程 <br /> Mini_Swoole_manager: 为 manager 进程<br /> Mini_Swoole_task: N 个 task 进程 <br /> Mini_Swoole_worker: M 个 worker 进程 <br />

<hr />

HTTP 服务

  • 将 http 段的enable 设置为 true, 其他服务设置为 false <br />
  • sh shell/socket.sh restart 重启服务 <br />
  • ps -ef | grep Mini 将看到 <br />

    Mini_Swoole_http_master: 为 master 进程 <br /> Mini_Swoole_manager: 为 manager 进程<br /> Mini_Swoole_task: N 个 task 进程 <br /> Mini_Swoole_worker: M 个 worker 进程 <br />

<hr />

Websocket 服务

  • 将 websocket 段的enable 设置为 true, 其他服务设置为 false <br />
  • sh shell/socket.sh restart 重启服务 <br />
  • ps -ef | grep Mini 将看到 <br />

    Mini_Swoole_websocket_master: 为 master 进程 <br /> Mini_Swoole_manager: 为 manager 进程<br /> Mini_Swoole_task: N 个 task 进程 <br /> Mini_Swoole_worker: M 个 worker 进程 <br />

<hr />
注: N 和 M 由 $config['common']['worker_num'] 与 $config['common']['task_worker_num'] 指定 <br />
<hr />

TCP 服务之控制器

  • 为了将控制权由 onReceive 转至控制器, 客户端发送的数据需要指定处理该请求的 module (默认是index, 可以忽略), controller 及 action, 比如要指定由 Tcp 控制器下的 login() 来处理, 则发送的数据中应该是这样的 json 格式:【参见client/tcp_client.php】
$data = [];
$data['controller'] = 'tcp';
$data['action']     = 'login';
$data['username']   = 'dym';
$data['password']   = md5(123456);
$cli->send(json_encode($data)."\r\n");
  • 如果 Controller 不存在, 客户端收到: Controller $controller not found<br />
  • 如果 action 不存在, 客户端收到: Method $action not found<br />
  • 请以 $config['common']['package_eof'] 指定的方式分包, 默认是 \r\n <br />
  • 控制器中的 $this->data 为客户端发过来的完整数据, 格式为数组 <br />
  • 控制器的方法中调用 $this->response($rep) 将数据发送至客户端<br />
  • 控制器的示例为 controller下的 Tcp.php<br />
  • 更多 tcp server 信息请参考 https://wiki.swoole.com/wiki/page/p-server.html
// login 及参数过滤
public function login(){
    try{
        // 过滤
        $username = $this->getParam('username');
        $password = $this->getParam('password');

        // 回复给客户端
        $this->response('Username => '.$username.', password => '.$password);

        // 不过滤
        $username = $this->getParam('username', FALSE);
        $this->response('Username => '.$username.', password => '.$password);
    }catch (Throwable $e){
        $this->error($e);
    }
}
<hr />

UDP 服务之控制器

  • 为了将控制权由 onReceive 转至控制器, 客户端发送的数据需要指定处理该请求的 module(默认是index, 可以忽略), controller 及 action, 比如要指定由 Udp 控制器下的 login() 来处理, 则发送的数据中应该是这样的 json 格式:【参见client/udp_client.php】
$client = new Swoole\Client(SWOOLE_SOCK_UDP, SWOOLE_SOCK_ASYNC);

$client->on("connect", function(swoole_client $cli) {
    $d = [];
    $d['controller']  = 'udp';
    $d['action']      = 'login';
    $d['username'] = 'fooDELETE FROM sl_table <script>dym</script>';
    $d['password'] = 'fooDELETE 123123</script>';
    $data = json_encode($d);

    $cli->send($data);
});

$client->on("receive", function(swoole_client $cli, $data){
    print_r($data);
});

$client->on("error", function(swoole_client $cli){
    
});

$client->on("close", function(swoole_client $cli){
    
});

$client->connect('127.0.0.1', 9502, 0.5);
  • 如果 Controller 不存在, 客户端收到: Controller $controller not found<br />
  • 如果 action 不存在, 客户端收到: Method $action not found<br />
  • 控制器中的 $this->data 为客户端发过来的完整数据, 格式为数组 <br />
  • 控制器的方法中调用 $this->response($rep) 将数据发送至客户端<br />
  • 控制器的示例为 controller下的 Udp.php<br />
  • 更多 udp server 信息请参考 https://wiki.swoole.com/wiki/page/p-server.html
public function udp(){
    try{
        $key = $this->getParam('key');
        $this->response('Your key is '.$key);
    }catch (Throwable $e){
        $this->error($e);
    }
}
<hr />

HTTP 服务之控制器

  • 根目录的 controller 的 Index.php/index(), 负责处理 http 的 index 事件, 也就是首页<br />
  • 为了将控制权由 onRequest 路由至控制器, 客户端应该在URL中指定处理该请求的 module (默认是index, 可以忽略), controller 及 action (默认是index, 可以忽略), 示例如下:
// ==== GET 的示例 ==== //
// Index 控制器下的 index() 来处理, 也就是首页, 则URL
http://127.0.0.1:9100

// Http 控制器下的 index() 来处理, 并且带上GET参数, 则URL
http://127.0.0.1:9100/http?username=dym&password=123456

// Http 控制器下的 login() 来处理, 并且带上GET参数, 则URL
http://127.0.0.1:9100/http/login?username=dym&password=123456

// ==== POST 的示例 ==== //
$url = 'http://127.0.0.1:9100/http/login';
$postData = [];
$postData['key'] = 'FOO';

$retval = HttpClient::post($url, $postData);
print_r($retval);

// Api模块的Login控制器下的 logout() 来处理, 则URL
http://127.0.0.1:9100/api/login/logout

// Api模块的User控制器下的 index() 来处理, 则URL
http://127.0.0.1:9100/api/user  
  • 暂时只支持 GET / POST 方法<br />
  • 如果 Controller 不存在, 客户端收到: Controller $controller not found<br />
  • 如果 action 不存在, 客户端收到: Method $action not found<br />
  • 控制器的方法中调用 $this->response->write($rep) 将数据发送至客户端, 可以调用多次 <br />
  • 控制器的示例为 controller下的 Index.php 与 Http.php 及 module/Api/controller 下的 Login.php 和 User.php <br />
  • 更多 http server 信息请参考 https://wiki.swoole.com/wiki/page/326.html
<hr />

Websocket 服务之控制器

  • 为了将控制权由 onMessage 转至控制器, 客户端发送的数据需要指定处理该请求的module (默认是index, 可以忽略), controller 及 action, 比如要指定由 websocket 控制器下的 go() 来处理, 则发送的数据中应该是这样的 json 格式:【参见client/ws.html】
var arr = {};
arr.controller = 'websocket';
arr.action     = 'go';
arr.key        = $('#key').val();
ws.send(JSON.stringify(arr));
  • 如果 Controller 不存在, 客户端收到: Controller $controller not found<br />
  • 如果 action 不存在, 客户端收到: Method $action not found<br />
  • 控制器中的 $this->data 为客户端发过来的完整数据,<br />
  • 控制器的方法中调用 $this->response($rep) 将数据发送至客户端<br />
  • 控制器的示例为 controller下的 Websocket.php<br />
  • 更多 websocket server 信息请参考 https://wiki.swoole.com/wiki/page/397.html
// Select all users
public function users(){
    try{
        $users = $this->m_user->SelectAll();
        $this->response(JSON($users));

        $key = $this->getParam('key');
        $this->response('Your key is '.$key);
    }catch (Throwable $e){
        $this->error($e);
    }
}
<hr />

MySQL

'mysql' => [
    'db'   => 'slave',
    'host' => '192.168.1.34',
    'port' => 3306,
    'user' => 'root',
    'pwd'  => '123456',
    'max'  => 3,
    'log_sql' => true,
],
  • 断线自动重连3次<br />
  • 配置文件中的 max 是指每一个 worker 有多少

Related Skills

View on GitHub
GitHub Stars10
CategoryDevelopment
Updated1y ago
Forks0

Languages

PHP

Security Score

75/100

Audited on Aug 18, 2024

No findings