(1). 项目根目录/test.php: => 使用默认消息协议
swoft有已经封装处理好的json-rpc调用,可以直接使用框架封装好的一些接口,也可以自己来写代码.
const RPC_EOL = "\r\n\r\n";
function request($host, $class, $method, $param, $version = '1.0', $ext = []) {
$fp = stream_socket_client($host, $errno, $errstr);
if (!$fp) {
throw new Exception("stream_socket_client fail errno={$errno} errstr={$errstr}");
}
$req = [
"jsonrpc" => '2.0',
"method" => sprintf("%s::%s::%s", $version, $class, $method),
'params' => $param,
'id' => '',
'ext' => $ext,
];
$data = json_encode($req) . RPC_EOL;
fwrite($fp, $data);
$result = '';
while (!feof($fp)) {
$tmp = stream_socket_recvfrom($fp, 1024);
if ($pos = strpos($tmp, RPC_EOL)) {
$result .= substr($tmp, 0, $pos);
break;
} else {
$result .= $tmp;
}
}
fclose($fp);
return json_decode($result, true);
}
// 替换服务器ip及端口,method格式为"{version}::{class_name}::{method_name}"
$ret = request('tcp://127.0.0.1:18307', \App\Rpc\Lib\ICourse::class, 'list', [1], "1.0");
var_dump($ret);
注:
①. 以上演示是在本地RPC项目,自己调用自己.
②. 如果需要在另外的地方使用,写上对方RPC的地址和接口拷贝到此项目即可.
(2). RPC服务端启动后,执行:php test.php:
array(2) {
["jsonrpc"]=>
string(3) "2.0"
["result"]=>
array(1) {
... // 得到的结果
}
}
(3). 总结:
上面实现了服务端提供一个RPC api,客户端通过stream_socket_client手动拼凑一个RPC协议来完成传输.
3. 延伸:
如果架构中有多个RPC服务,如订单、商品、库存、用户…业务N
3.1 缺点:
①. 全部像上面那样客户端写代码调用,会写很多份来分别调用(不方便).
②. 写的RPC服务给其它项目组、合作伙伴使用.如果第三方是go、java这些语言,不一定是按你写的代码来调用,这时候这样调用RPC就非常不方便.
③. 每个RPC api会有一些公共的东西,如鉴权、限流等功能.如果全部写在单独的RPC api中,很不方便了维护.
3.2 改进:
①. 客户端请求网关api,网关把请求转发给真实RPC api.(内部RPC服务还是可以直接请求RPC api).
②. 把公共的东西全部抽离出来,变成由专门的网关统一完成.
③. 网关有现成的,也有定制的.相结合的话,更能适合自己的场景.