Swoole RPC 的实现
概述
这是关于 Swoole 学习的第七篇文章:Swoole RPC 的实现。
- 第六篇:Swoole 整合成一个小框架
- 第五篇:Swoole 多协议 多端口 的应用
- 第四篇:Swoole HTTP 的应用
- 第三篇:Swoole WebSocket 的应用
- 第二篇:Swoole Task 的应用
- 第一篇:Swoole Timer 的应用
有位读者说 “上篇文章,下载代码后直接运行成功,代码简洁明了,简直是 Swoole 入门最好的 Demo ”。
“哈哈哈...”
还有读者说 “有一起学习的组织群吗,可以在里面进行疑难答疑?”
这个还真没有,总觉得维护一个微信群不容易,因为自己本身就不爱在群里说话,另外,自己也在很多微信群中,开始氛围挺好的,大家都聊聊技术,后来技术聊的少了改成聊八卦啦,再后来慢慢就安静了,还有在群里起冲突的...
当然我也知道维护一个微信群的好处是非常大的,如果有这方面经验的同学,咱们一起交流交流 ~
还有出版社找我写书的.
他们也真是放心,我自己肚子里几滴墨水还是知道的,目前肯定是不行,以后嘛,再说。
还有一些大佬加了微信,可能是出于对晚辈的提携吧,偷偷告诉你,从大佬的朋友圈能学到很多东西。
我真诚的建议,做技术的应该自己多总结总结,将自己会的东西写出来分享给大家,先不说给别人带来太多的价值,反正对自己的帮助是非常非常大的,这方面想交流的同学,可以加我,我可以给你无私分享。
可能都会说时间少,时间只要挤,总会有的,每个人都 24 小时,时间对每个人是最公平的。说到这推荐大家读一下《暗时间》这本书,这是我这本书的 读书笔记,大家可以瞅瞅。
开始今天的文章吧,这篇文章实现了一个简单的 RPC 远程调用,在实现之前需要先了解什么是 RPC,不清楚的可以看下之前发的这篇文章 《我眼中的 RPC》。
下面的演示代码主要使用了 Swoole 的 Task 任务池,通过 OnRequest/OnReceive 获得信息交给 Task 去处理。
举个工作中的例子吧,在电商系统中的两个模块,个人中心模块和订单管理模块,这两个模块是独立部署的,可能不在一个机房,可能不是一个域名,现在个人中心需要通过 用户ID 和 订单类型 获取订单数据。
实现效果
客户端
- HTTP 请求
//代码片段
<?php
$demo = [
'type' => 'SW',
'token' => 'Bb1R3YLipbkTp5p0',
'param' => [
'class' => 'Order',
'method' => 'get_list',
'param' => [
'uid' => 1,
'type' => 2,
],
],
];
$ch = curl_init();
$options = [
CURLOPT_URL => 'http://10.211.55.4:9509/',
CURLOPT_POST => 1,
CURLOPT_POSTFIELDS => json_encode($demo),
];
curl_setopt_array($ch, $options);
curl_exec($ch);
curl_close($ch);
- TCP 请求
//代码片段
$demo = [
'type' => 'SW',
'token' => 'Bb1R3YLipbkTp5p0',
'param' => [
'class' => 'Order',
'method' => 'get_list',
'param' => [
'uid' => 1,
'type' => 2,
],
],
];
$this->client->send(json_encode($demo));
请求方式
SW 单个请求,等待结果
发出请求后,分配给 Task ,并等待 Task 执行完成后,再返回。
SN 单个请求,不等待结果
发出请求后,分配给 Task 之后,就直接返回。
发送数据
$demo = [
'type' => 'SW',
'token' => 'Bb1R3YLipbkTp5p0',
'param' => [
'class' => 'Order',
'method' => 'get_list',
'param' => [
'uid' => 1,
'type' => 2,
],
],
];
- type 同步/异步设置
- token 可进行权限验证
- class 请求的类名
- method 请求的方法名
- uid 参数一
- type 参数二
返回数据
- request_method 请求方式
- request_time 请求开始时间
- response_time 请求结束时间
- code 标识
- msg 标识值
- data 约定数据
- query 请求参数
代码
OnRequest.php
<?php
if (!defined('SERVER_PATH')) exit("No Access");
class OnRequest
{
private static $query;
private static $code;
private static $msg;
private static $data;
public static function run($serv, $request, $response)
{
try {
$data = decrypt($request->rawContent());
self::$query = $data;
if (empty($data)) {
self::$code = '-1';
self::$msg = '非法请求';
self::end($request, $response);
}
//TODO 验证Token
switch ($data['type']) {
case 'SW': //单个请求,等待结果
$task = [
'request' => $data,
'server' => 'http'
];
$rs = $serv->task(json_encode($task), -1, function ($serv, $task_id, $rs_data) use ($request, $response) {
self::$code = '1';
self::$msg = '成功';
self::$data = $rs_data['response'];
self::end($request, $response);
});
if ($rs === false) {
self::$code = '-1';
self::$msg = '失败';
self::end($request, $response);
}
break;
case 'SN': //单个请求,不等待结果
$task = [
'request' => $data,
'server' => 'http'
];
$rs = $serv->task(json_encode($task));
if ($rs === false) {
self::$code = '-1';
self::$msg = '失败';
} else {
self::$code = '1';
self::$msg = '成功';
}
self::end($request, $response);
break;
default:
self::$code = '-1';
self::$msg = '非法请求';
self::end($request, $response);
}
} catch(Exception $e) {
}
}
private static function end($request = null, $response = null)
{
$rs['request_method'] = $request->server['request_method'];
$rs['request_time'] = $request->server['request_time'];
$rs['response_time'] = time();
$rs['code'] = self::$code;
$rs['msg'] = self::$msg;
$rs['data'] = self::$data;
$rs['query'] = self::$query;
$response->end(json_encode($rs));
self::$data = [];
return;
}
}
OnReceive.php
<?php
if (!defined('SERVER_PATH')) exit("No Access");
class OnReceive
{
private static $request_time;
private static $query;
private static $code;
private static $msg;
private static $data;
public static function run($serv, $fd, $reactor_id, $data)
{
try {
self::$request_time = time();
$data = decrypt($data);
self::$query = $data;
//TODO 验证Token
switch ($data['type']) {
case 'SW': //单个请求,等待结果
$task = [
'fd' => $fd,
'request' => $data,
'server' => 'tcp',
'request_time' => self::$request_time,
];
$rs = $serv->task(json_encode($task));
if ($rs === false) {
self::$code = '-1';
self::$msg = '失败';
self::handlerTask($serv, $fd);
}
break;
case 'SN': //单个请求,不等待结果
$task = [
'fd' => $fd,
'request' => $data,
'server' => 'tcp',
'request_time' => self::$request_time,
];
$rs = $serv->task(json_encode($task));
if ($rs === false) {
self::$code = '-1';
self::$msg = '失败';
} else {
self::$code = '1';
self::$msg = '成功';
}
self::handlerTask($serv, $fd);
break;
default:
self::$code = '-1';
self::$msg = '非法请求';
self::handlerTask($serv, $fd);
}
} catch(Exception $e) {
}
}
private static function handlerTask($serv, $fd)
{
$rs['request_method'] = 'TCP';
$rs['request_time'] = self::$request_time;
$rs['response_time'] = time();
$rs['code'] = self::$code;
$rs['msg'] = self::$msg;
$rs['data'] = self::$data;
$rs['query'] = self::$query;
$serv->send($fd, json_encode($rs));
}
}
小结
Demo 代码仅供参考,里面有很多不严谨的地方!
服务的调用方与提供方中间需要有一个服务注册中心,很显然上面的代码中没有,需要自己去实现。
服务注册中心,负责管理 IP、Port 信息,提供给调用方使用,还要能负载均衡和故障切换。
根据自己的情况,服务注册中心实现可容易可复杂,用 Redis 也行,用 Zookeeper、Consul 也行。
感兴趣的也可以了解下网关 Kong ,包括 身份认证、权限认证、流量控制、监控预警...
再推荐一个 Swoole RPC 框架 Hprose,支持多语言。
就到这了,上面的 Demo 需要源码的,加我微信。(菜单-> 加我微信-> 扫我)
本文欢迎转发,转发请注明作者和出处,谢谢!
Swoole RPC 的实现的更多相关文章
- Swoole MySQL 连接池的实现
目录 概述 代码 扩展 小结 概述 这是关于 Swoole 入门学习的第八篇文章:Swoole MySQL 连接池的实现. 第七篇:Swoole RPC 的实现 第六篇:Swoole 整合成一个小框架 ...
- Swoole Redis 连接池的实现
概述 这是关于 Swoole 入门学习的第九篇文章:Swoole Redis 连接池的实现. 第八篇:Swoole MySQL 连接池的实现 第七篇:Swoole RPC 的实现 第六篇:Swoole ...
- 压测 swoole_websocket_server 性能
概述 这是关于 Swoole 入门学习的第十篇文章:压测 swoole_websocket_server 性能. 第九篇:Swoole Redis 连接池的实现 第八篇:Swoole MySQL 连接 ...
- Swoole和Swoft的那些事 (Http/Rpc服务篇)
https://www.jianshu.com/p/4c0f625d5e11 Swoft在PHPer圈中是一个门槛较高的Web框架,不仅仅由于框架本身带来了很多新概念和前沿的设计,还在于Swoft是一 ...
- Swoft 源码剖析 - Swoole和Swoft的那些事 (Http/Rpc服务篇)
前言 Swoft在PHPer圈中是一个门槛较高的Web框架,不仅仅由于框架本身带来了很多新概念和前沿的设计,还在于Swoft是一个基于Swoole的框架.Swoole在PHPer圈内学习成本最高的工具 ...
- php的swoole和rpc区别
RPC是远程过程调用(Remote Procedure Call)的缩写形式. SAP系统RPC调用的原理其实很简单,有一些类似于三层构架的C/S系统,第三方的客户程序通过接口调用SAP内部的标准或自 ...
- 房产基于Swoole的PHP RPC框架设计
房产基于Swoole的PHP RPC框架设计 https://mp.weixin.qq.com/s/XSrKEQ-0q4DvjOGTIwYYzg
- swoole 使用 1
在很长的一段时间里,我不太看好swoole,发现它的文档太少,社区也不够活跃等,但是最近在学习 Hprose时,发现swoole在rpc方面做得更加完善,于是决定看看. 在简单的使用swoole扩展后 ...
- FastRPC 3.2 发布,高性能 C++ 协程 RPC 框架
用过go erlang gevent的亲们应该都会知道协程在应用中带来的方便. 如果对协程不理解的同学,通过阅读下面例子可以快速了解我们框架的协程的意义,已了解的可以跳过这部分. 协程例子:假设我们要 ...
随机推荐
- AOP面向切面编程笔记
1.AOP概念:Aspect Oriented Programming 面向切面编程 2.作用:本质上来说是一种简化代码的方式 继承机制 封装方法 动态代理 …… 3.情景举例 ①数学计算器接口[Ma ...
- Linux学习-灾难复原的考虑
硬件损毁,且具有完整备份的数据时 由于是硬件损毁,所以我们不需要考虑系统软件的不稳定问题,所以可以直接将完整的系统复原回去 即可. 由于软件的问题产生的被攻破资安事件 由于系统的损毁是因为被攻击,此时 ...
- 1512 Monkey King
Monkey King Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Tota ...
- Leetcode37--->Sudoku Solver(填充数独)
题目: 给定一个不完整的数独,要求填充好数独:最初给出的数独是有效的,且假设一定有答案: 举例: A sudoku puzzle... 解题思路: 该题与青蛙走迷宫问题很相似,都是用深度优先: 代码如 ...
- python 学习分享-基础篇
1.python起手式 写下第一个代码,打印‘hello world’ print('hello world') 2.变量 变量是为了存储信息,在程序中被调用,标识数据名称或类型. 变量定义的规则: ...
- HTTP LVS
1. Configure the director 2.
- Android SDK Manager 报错:Connection to https://dl-ssl.google.com refused
Connection to https://dl-ssl.google.com refused. OR Failed to fectch URl https://dl-ssl.google.com/a ...
- linux 系统时间调整
linux的硬件时间是从COMS中读取的. 系统时间是由操作系统维护的. 先查看时区是否正确 (东八区 +8) #date -R 选择时区: #tzselect 修改了系统时间,还应该跟硬件时间进行同 ...
- Java容器jdk1.6 Array
参考:https://www.cnblogs.com/tstd/p/5042087.html 1.定义 顶层接口collection public interface Collection<E& ...
- 【bzoj1907】树的路径覆盖 树形dp
题目描述 输入 输出 样例输入 1 7 1 2 2 3 2 4 4 6 5 6 6 7 样例输出 3 题解 树形dp 设f[x]表示以x为根的子树完成路径覆盖,且x为某条路径的一端(可以向上延伸)的最 ...