MiniSwoole
Mini Swoole for TCP, UDP, HTTP, Websocket framework based on Swoole
Install / Use
/learn @xwmhmily/MiniSwooleREADME
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 管理
环境要求
- PHP >= 7.0 <br />
- swoole, 建议 2.2.0 <br />
- pdo <br />
- redis <br />
- pdo_mysql <br />
安装
- Git clone 至任一目录
- 创建数据库并导入SQL 文件
配置
- 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 对应的参数
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 />
心跳检测
- 利用Crond 定时运行 shell/socket.sh heartbeat 即可<br />
使用
- 采用 Module-Controll-Model 模式, 所有的请求均转至 Module-Controller下处理 <br />
- 默认 Module 为index, 无须声明, 对应的控制器文件位是根目录的 controller<br />
- 在配置文件的 module 中声明新模块,以英文逗号分隔,如 'Api, Admin, Mall, Shop', 对应的控制器文件是 /module/$moduleName/controller<br />
- 中间件:很多时候,我们需要在请求前与后做一些前置与后置的统一业务,比如授权认证,日志与流量收集,中件间就派上用场了。
日志和错误处理
- 系统的错误文件由 $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 />
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 />
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 />
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 />
注: 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
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
node-connect
354.0kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
112.2kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
354.0kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
354.0kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
