swover / swover
A Server-Framework based on Swoole extension
Installs: 4 665
Dependents: 0
Suggesters: 0
Security: 0
Stars: 13
Watchers: 2
Forks: 2
Open Issues: 0
Requires
- php: >=5.6
- ext-pcntl: *
- ext-posix: *
- ext-swoole: >=1.9.5
Requires (Dev)
- phpunit/phpunit: ^5
This package is auto-updated.
Last update: 2024-03-29 03:51:22 UTC
README
Swover是一个基于Swoole扩展的服务类库,提供基础的HTTP、TCP、Process服务能力,不包含任何业务代码,只需简单配置即可安全使用,对业务代码完全无侵入。
依赖
- PHP 5.6 及之后版本
- Swoole Extension 1.9.5 及更新版本
- pcntl-extension
- posix-extension
虽然提供了对 PHP5 及 swoole 1.x 的支持,但仍建议升级到最新版。
安装
添加swover到composer.json文件,然后更新composer。
$ composer require swover/swover
$ composer update
配置项
配置 | 类型 | 场景 | 必填 | 默认 | 描述 |
---|---|---|---|---|---|
server_type | string | all | Y | 服务类型,可选项:http,tcp,process | |
daemonize | bool | all | N | false | 服务是否以守护进程方式运行 |
process_name | string | all | N | server | 服务的进程名,单节点内应唯一 |
worker_num | int | all | N | 1 | worker 进程数 |
task_worker_num | int | tcp,http | N | 0 | task-worker 进程数 |
host | string | tcp,http | N | 0.0.0.0 | 监听地址 |
port | int | tcp,http | N | 0 | 监听端口,0 表示随机获取一个可用端口 |
max_request | int | all | N | 0 | 进程最大执行次数,超过时安全重启。0 表示永不重启,为避免内存泄漏,建议设置 |
entrance | string | all | Y | 业务逻辑的入口,必须是可被调用的函数或方法,接收request 返回response |
|
async | bool | tcp,http | N | false | 是否异步执行,如果为true ,接收到请求后,转发给task 异步处理 |
setting | array | all | N | 配置选项 | |
events | array | all | N | 事件注册,支持二维数组,数组下标无实际作用。事件 |
开始使用
服务类型
Swover
提供了三种服务类型可用:
- Tcp:
Tcp
类型的服务基于\Swoole\Server
处理网络请求与响应 - Http:
Http
类型的服务基于\Swoole\Http\Server
处理网络请求与响应 - Process:通过
\Swoole\Process
创建子进程,在进程内执行while(true)
调用业务入口,需在入口内处理输入输出
通过服务启动时传入的server_type
配置项决定服务类型。
启停服务
$config = [ 'server_type' => 'tcp', 'daemonize' => false, 'process_name' => 'swover', 'worker_num' => 2, //会被setting内的同名配置覆盖 'task_worker_num' => 1, 'max_request' => 0, 'entrance' => '\\Entrance::process', 'host' => '127.0.0.1', 'port' => '9501', 'async' => false, 'setting' => [ 'worker_num' => 3, //覆盖外层同名配置,最终服务启动时的 worker_num 为 3 'log_file' => '/tmp/swoole_tcp.log', ], 'events' => [ //事件注册可以为字符串、对象、闭包 'master_start' => [ '\MasterStartA', new \MasterStartB(), ], 'worker_start' => '\WorkerStart', function ($request) { }, ] ]; $class = new \Swover\Server($config); $class->start(); //启动服务 //$class->stop(); //安全的停止服务 //$class->force(); //强制停止 //$class->restart(); //安全的重启服务 //$class->reload(); //安全的重新加载服务
服务启动后,通过Request
接收客户端请求,将Request
对象作为参数传递给入口函数。
入口函数处理完业务逻辑后返回结果,建议返回Response
对象、字符串或布尔值。
Request
服务接收到客户端数据后,构造\Swover\Utils\Request
对象,构造函数接收参数为:
\Swoole\Http\Request
:HTTP服务类型array
:TCP服务类型
对象继承自\ArrayObject
,可通过$request['get']
、$request->get
或$request->get()
获取请求参数。
// curl http://127.0.0.1:9501/user/info?id=123 function entrance(\Swover\Utils\Request $request) { var_dump($request->path()); // string(10) "/user/info" var_dump($request->get()); // array(1) { // ["id"]=> // string(3) "123" // } var_dump($request->get('name', 'ruesin')); // string(6) "ruesin" var_dump($request->get); // array(1) { // ["id"]=> // string(3) "123" // } var_dump($request->get['id']); // string(3) "123" }
由于
Process
服务只是通过while(true)
调用入口函数,所以传递给入口函数的是一个空的Request
对象。
Response
入口函数完成后返回数据,构造\Swover\Utils\Response
对象,响应结果到客户端,数据类型:
\Swover\Utils\Response
对象- 字符串:构造
Response
对象,设置字符串为响应消息体; - 布尔值:构造
Response
对象,如果false
设置status
为500,否则为200
Response 实现:
// \Swover\Server\Base::class protected function entrance($request) { $result = call_user_func_array($this->entrance, [$request]); if ($result instanceof \Swover\Contracts\Response) { $response = $result; } else { $response = new Response(); } if (is_string($result) || is_numeric($result)) { $response->setBody($result); } if (is_bool($result) && $result === false) { $response->setCode(500); } return $response; }
业务入口:
// 返回字符串,将被设置为 response body function entranceA(\Swover\Utils\Request $request) { return "This is response body."; } // 返回 false,将 http code 设置为500 function entranceB(\Swover\Utils\Request $request) { return false; } // 返回 response 对象 function entranceC(\Swover\Utils\Request $request) { $response = new \Swover\Utils\Response(); $response->setBody('{"status":-1,"msg":"Has Not Route!"}'); $response->setCode(404); $response->setHeader('Content-Type', 'application/json'); return $response; }
在
Process
服务中,当status
大于400时,判定终止此次循环,将重启worker进程。
Event
提供了事件机制,可以通过服务启动前传入配置 或 调用\Swover\Utils\Events
注册事件。
此处提供的事件,主要是为了扩展Swoole的事件回调,事件按照注册顺序先后触发,可使用Event::before()
方法将方法插入队头。
注册的回调方法:
- 自定义类:必须有表示事件类型的
EVENT_TYPE
静态属性,时间触发的trigger(...$params)
方法 - 闭包
function(...$params){}
除Request
和Response
两个事件为特殊定义,其余事件的参数均须与Swoole事件严格一致。
支持的事件类型定义在\Swover\Contracts\Events
接口中,建议绑定事件时直接使用预定义常量,避免触发失败。
事件类型大小写不敏感,最终绑定均转为小写。
TCP的receive
和HTTP的request
事件统一为request
事件,参数及使用定义在\Swover\Utils\Event\Request
。
response
事件参数及使用定义在\Swover\Utils\Event\Response
。
$instance = \Swover\Utils\Event::getInstance(); // 绑定闭包 $instance->bindInstance(\Swover\Contracts\Events::START, 'master_start_alias_a', function (\Swoole\Server $server) { echo "Swoole server is started\n"; }); // 绑定对象 $instance->bind(new WorkerStartEvent()); // 绑定类名,自动解析为对象 $instance->bind('WorkerStartEvent'); //自定义类,必须定义 EVENT_TYPE、trigger() class WorkerStartEvent { const EVENT_TYPE = \Swover\Contracts\Events::WORKER_START; public function trigger($server, $worker_id) { echo $worker_id . PHP_EOL; } } // 实现了 Request 接口,接口已定义 EVENT_TYPE,只需实现 trigger() class RequestEvent implements \Swover\Contracts\Events\Request { public function trigger($server, $request) { echo $request->path . PHP_EOL; } }
Worker
提供获取当前进程状态、主进程状态的方法。
父进程收到SIGCHLD
信号后,子进程调用Worker::getStatus()
时,会触发pcntl_signal_dispatch()
注册的事件,将当前进程状态设置为false
。
利用此特性,在业务内判断当前进程的状态是否需要退出。
while(true) { if (\Swover\Worker::getStatus() == false) { echo "Worker process is finish."; break; } //do something }
Worker::checkProcess($pid)
用来检测指定进程ID是否正常存活,可用于在子进程中检测父进程的状态,当父进程不存在时退出当前进程。
while(true) { if (\Swover\Worker::checkProcess(\Swover\Worker::getMasterPid()) == false) { echo "Parent process has gone away."; break; } //do something }