swoolefy是基于swoole实现的轻量级高性能框架,框架支持http,websocket,udp服务器,以及基于tcp实现可扩展的rpc服务,同时支持composer包方式安装部署项目。基于实用,swoolefy抽象Event事件处理类,实现与底层的回调的解耦,支持同步|异步调用,内置view、log、session、mysql、redis、memcached、mongodb等常用组件等。 swoolefy经过多个版本的迭代和实践,以及优化,性能稳定,目前已经至1.0.6版本。 1.0.6版本主要的更新:
github:https://github.com/bingcool/swoolefy 文档:https://www.kancloud.cn/bingcoolhuang/php-swoole-swoolefy/587501 下面是一个rpc的demo: RPC的服务端:1、设置协议层配置文件protocol/rpc/config.php,添加packet设置: 'packet'=>[ // 服务端使用长度检查packet时,设置包头结构体,如果使用eof时,不需要设置,底层会读取package_eof 'server'=>[ 'pack_header_struct' => ['length'=>'N', 'version'=>'a10', 'name'=>'a30', 'request_id'=>'a12'], 'pack_length_key' => 'length', 'serialize_type' => 'json' ], //客户端解包设置 'client' => [ 'pack_check_type' => 'length', 'pack_header_struct' => ['length'=>'N', 'version'=>'a10', 'name'=>'a30', 'request_id'=>'a12'], 'pack_length_key' => 'length', 'serialize_type' => 'json' ] ], 2、服务端的控制器中 <?php
namespace Service\Coms\Book;
use Swoolefy\Core\Swfy;
use Swoolefy\Core\SController;
use Swoolefy\Core\Application;
use Swoolefy\Core\Task\TaskManager;
class BookmanageService extends SController {
public function test($params) {
// 客户端发送过来的数据
var_dump($params);
$data = $params;
//客户端的头部与服务端头部相同,当然可以根据返回数据不同,返回包头可以不同。
$header = ['length'=>'', 'version'=>'1.0.1', 'name'=>'bingcool', 'request_id'=>$this->getRpcPackHeader()['request_id']];
// 返回数据给客户端
$this->send($this->fd, $data, $header);
}至此,很很简单的服务端就ok了,其实就是设置一下packet就可以了。 RPC的客户端:client端是基于swoole_client实现的,所以环境中必须安装swoole和swoole_serialize扩展。这个客户端其实是可以用在Apache|php-fpm的环境中,并且支持并行调用。 1、在/protocol/rpc/RpcServer.php的onWorkerStart中注册client的访问的服务,或者在start_init配置项中的类的onWorkerStart函数中注册服务,因为该类必须继承于Swoolefy\Core\StartInit的。 /**
* onWorkerStart
* @param $server
* @return
*/
public function onWorkerStart($server, $worker_id) {
if(Swfy::isWorkerProcess()) {
$productServiceConfig = [
'servers' => '127.0.0.1:9504',
'timeout' => 0.5,
'noblock' => 0
];
$orderServiceConfig = array(
'servers' => '127.0.0.1:9506',
'timeout' => 0.5,
'noblock' => 0
);
//客户端pack长度检查设置
$setting = array(
'open_length_check' => 1,
'package_length_type' => 'N',
'package_length_offset' => 0, //第N个字节是包长度的值
'package_body_offset' => 56, //第几个字节开始计算长度
'package_max_length' => 2000000, //协议最大长度
);
// 包头结构体设置,默认客户端与服务端包头结构体相同
$header_struct = array(
'length'=>'N',
'version'=>'a10',
'name'=>'a30',
'request_id'=>'a12'
);
// 注册product服务
RpcClientManager::getInstance(true)->registerService('productService', productServiceConfig, $setting, $header_struct,[
// swoole_client 长连接
'swoole_keep' => false
]);
// 注册order服务
RpcClientManager::getInstance(true)->registerService('orderService', $orderServiceConfig, $setting, $header_struct,[
// swoole_client 长连接
'swoole_keep' => true
]);
}
}2、在controller或者model中可以直接调用向服务端发送数据 public function test() {
$callable = 'Service\Coms\Book\BookmanageService::test';
$params = ['content'=>'我是rpc的客户端,我向你发送消息'];
$header = ['length'=>'', 'version'=>'1.0.0', 'name'=>'bingcool'];
//调用发送数据
$client1 = RpcClientManager::getInstance()->getServices('productService')->buildHeaderRequestId($header)->waitCall($callable, $params);
//阻塞等待数据返回
$res1 = $client1->waitRecv();
var_dump($res1);
}上面将返回一个数据,数组里有两个元素,arr[0]是包头,arr[1]是包体数据,例如: array(2) {
[0] => array(4) {
["length"] => int(83)
["version"] => string(10) "1.0.0"
["name"] => string(30) "bingcool"
["request_id"] => string(12) "d189dfd5b997"
}
[1] => array(4) {
["content"] => array(1) {
["content"] => string(16) "我是rpc的服务端,我已收到你发送的消息"
}
}b、并行调用,然后在时间内等待接收所有数据,再进行数据聚合 // productService 调用
$callable = 'Service\Coms\Book\BookmanageService::test';
$params = ['content'=>'hhhhhhhhhhhhhhhh'];
$header = ['length'=>'', 'version'=>'1.0.1', 'name'=>'bingcool'];
$client2 = RpcClientManager::getInstance()->getServices('productService')->buildHeaderRequestId($header)->waitCall($callable, $params);
// orderService 调用
$callable = 'Service\Coms\Book\BookmanageService::test';
$params = ['content'=>'hhhhhhhhhhhhhhhh'];
$header = ['length'=>'', 'version'=>'1.0.1', 'name'=>'bingcool'];
$client3 = RpcClientManager::getInstance()->getServices('orderService')->buildHeaderRequestId($header)->waitCall($callable, $params);
// productService 调用
$callable = 'Service\Coms\Book\BookmanageService::test';
$params = ['content'=>'hhhhhhhhhhhhhhhh'];
$header = ['length'=>'', 'version'=>'1.0.1', 'name'=>'bingcool'];
$client4 = RpcClientManager::getInstance()->getServices('productService')->buildHeaderRequestId($header)->waitCall($callable, $params);
// productService 调用
$callable = 'Service\Coms\Book\BookmanageService::test';
$params = ['content'=>'hhhhhhhhhhhhhhhh'];
$header = ['length'=>'', 'version'=>'1.0.1', 'name'=>'bingcool'];
$client5 = RpcClientManager::getInstance()->getServices('productService')->buildHeaderRequestId($header)->waitCall($callable, $params);
// 并行等待数据返回,这里返回的是所有调用的数据,例如上面调用4次,那么将返回给数组$res中4个整包元素
$res = RpcClientManager::getInstance()->multiRecv();
var_dump($res);
~~~
那么如何获取其中某一个的客户端的数据呢,很简单
~~~
// 获取整包数据,包括包头和包体
$pack_data = $client2->getResponsePackData();
// 分离包头包体
list($pack_header, $pack_body) = $pack_data;
// 直接获取包头
$pack_header = $client2->getResponsePackHeader();
或者
$pack_header = $pack_data[0];
// 直接获取包头
$pack_body = $client2->getResponsePackBody();
或者
$pack_body = $pack_data[1];这是一个简单的说明,具体可以参考文档。 |