PHP实现RPC(简版)
概述
RPC这个东西是什么? 第一次听说他, 还要在它的前边加个G, 当时我以为GRPC是一项技术, 后来才知道, 并不是这样. GRPC只是RPC的谷歌实现.
谷歌搜了一下, RPC就是一种: 远程函数调用, 看到这里, 我已经等不及了, 不往下看了, 先自己实现一个. 如果只给你这样一个概念, 如何实现调用远程函数的功能呢?
自己实现
自己尝试实现一个粗糙的PHP版本. (不想看可以跳过的)
思路
远程调用, 只需要解决下面问题:
- 通信问题
- 定义传输的数据格式
- 如何封装后可以达到像调用本地函数一样的效果
先来解决通信问题, 直接粗暴的tcp socket
传输的数据格式, 直接用json进行传输
调用本地函数?? 这就要借助一下PHP的魔术函数了, __call()
这个函数是一个类调用不存在的方法时会跑到这里来, 所以, 我们返回一个类, 在call
方法中进行远程调用, 这样, 在本地看来就只是在调用一个方法.
开始实现
PHP中进行socket连接十分简单, 直接调用系统函数. 通信问题解决了, 剩下的就是传输数据了, so easy
经过一番摸索, 看下结果
服务器内容:
<?php
class RpcServer{private $port = 0; // 监听端口号private $host = ''; // IPpublic function __construct($host, $port){$this->host = $host;$this->port = $port;}/*** 运行, 监听端口并处理*/public function run(){// 创建socket$server = stream_socket_server("tcp://{$this->host}:{$this->port}");if(empty($server)) throw new Exception('创建套接字失败');// 监听while (true){$client = stream_socket_accept($server);if(empty($client)) continue;// 处理请求$this->disposeClient($client);fclose($client);}}private function disposeClient($client){$buf = fread($client, 4096);$array = json_decode($buf, true);// 创建对象并调用方法$class = $array['class'] ?? '';$method = $array['method'] ?? '';$params = $array['params'] ?? [];$instance = new $class();$result = $instance->$method(...$params);fwrite($client, json_encode($result));}
}
// 测试调用类
class Test{public function tt(){return 'return_tt';}public function add($a, $b){return $a + $b;}
}(new RpcServer('127.0.0.1', 8888))->run();
调用方:
<?php
class RpcClient{private $urlInfo = null;private $className = '';private function __construct($url, $className){$this->urlInfo = parse_url($url);$this->className = $className;}public static function getInstance($className){return new RpcClient('127.0.0.1:8888', $className);}public function __call($name, $arguments){// 创建客户端$client = stream_socket_client("tcp://{$this->urlInfo['host']}:{$this->urlInfo['port']}");if(empty($client)) return null;// 发送数据fwrite($client, json_encode(['class' => $this->className,'method' => $name,'params' => $arguments,]));// 接收返回$data = fread($client, 4096);// 关闭客户端fclose($client);return json_decode($data, true);}
}$test = RpcClient::getInstance('Test');
echo $test->tt(), PHP_EOL;
echo $test->add(4, 6);
结果:
嗯, 还阔以. 当然, 问题还是有很多的, 比如不能实现保存对象的修改状态等等.
其实对象可以通过序列化和反序列化来传输, 额, Java中, 不知道PHP有没有这种技术.
当然, 一个RPC中必然大量使用反射
、序列化
、动态加载
、代理
、网络请求
等等, 这只是一个超级超级粗糙的示例.
继续
nice, 自己做完了, 对RPC是个什么东西有了一个基本的概念.
WHAT
RPC是什么? 简单说, 就是远程函数调用. 字面意思, 很好理解.
WHY
看到一个技术, 一定会问的一个问题就是: 为什么? 一个技术基本不会平白无故出现, 都是为了解决某些问题, 那么RPC解决了什么问题呢? 字面含义: 远程函数调用
为什么要进行远程函数调用, 把函数拿过来本地调用不就好了? 还不用走网络IO, 速度更快一些. 很好, 现在假设, 你真的这样做了, 当项目变得庞大, 你想要进行拆分, 拆分后的有: 项目A, 项目B…, 这时, 你发现这些拆分的项目部分逻辑是重叠的, 比如用户信息相关, 怎么办? 如果不抽出来, 以后的维护成本会变得很高, 一处改处处改. 如果抽出来, 跨项目如何进行调用? 哎, 走过路过不要错过, RPC推荐给你.
HOW
那么如何实现RPC呢?
在刚才使用PHP简单实现中, 已经发现了. 需要解决的问题如下:
- 网络通信
- 信息格式
- 对象状态保存
1.网络通信
说到底, 网络通信不过两种: tcp udp.
有没有使用udp
实现的RPC呢? 貌似也有.
使用tcp
协议实现的RPC也有, 当然, 不光传输层协议, 也有直接通过应用层协议: http
、websocket
等等建立连接的. 当然, 如果需要频繁调用, 可以不断开tcp
连接, 在一段时间内一直保持连接, 避免频繁握手.
2.信息格式
信息格式就有很多选择了, json、xml等等, 也可以自己定制, 只要发送端和接收端统一信息格式就行了.
3.对象状态保存
对于一个类的调用, 通常都会有类状态修改的操作, 比如调用setName
方法, 如何保存对象的信息呢? 当然, 可以服务端将对象在内存中的信息直接序列化发回去, 当客户端下次调用时携带序列化信息, 服务端接收后反序列化还原对象继续操作.
过程
个人理解的RPC
调用过程:
- 客户端创建RPC对象
- 客户端调用方法
- RPC解析方法并将对象及参数做序列化
- RPC通过网络连接发送方法调用
- 服务端接收到方法调用, 解析对象及参数反序列化
- 服务端执行方法并将结果序列化返回
- 客户端接收到结果并进行解析, 返回给本地调用者
- 拿到最终结果
RPC适用于内部网络不同项目之间的通信, 如果是对外暴露的, 个人感觉还是通过接口的形式吧.
使用RPC显然会丧失一部分性能, 毕竟调用要走网络IO, 尽管是内网, 仍然要比本地调用慢上一些, 但带来了更好的可扩展性和可维护性, 感觉还是不错的.
之后如果用到的话, 拉个框架看看源码.
个人理解, 以上…
PHP实现RPC(简版)相关推荐
- 怎么改PHP_PHP实现RPC(简版)
概述 RPC这个东西是什么? 第一次听说他, 还要在它的前边加个G, 当时我以为GRPC是一项技术, 后来才知道, 并不是这样. GRPC只是RPC的谷歌实现. 谷歌搜了一下, RPC就是一种: 远程 ...
- [置顶]完美简版学生信息管理系统(附有源码)管理系统
简版学生信息管理系统 目前为止找到的简版系统中最新.最全的java类管理系统 点击进入简版系统 如果无法直接连接,请进入: https://blog.csdn.net/weixin_43419816/ ...
- 7句话让Codex给我做了个小游戏,还是极简版塞尔达,一玩简直停不下来
点击上方"视学算法",选择加"星标"或"置顶" 重磅干货,第一时间送达 梦晨 萧箫 发自 凹非寺 量子位 | 公众号 QbitAI 什么,7 ...
- 来,一起手撸一个简版 Redis(附源码)
点击上方 视学算法,选择 设为星标 优质文章,及时送达 作者 | 凯京技术团队 来自 | my.oschina.net/keking/blog/3037372 今天主要介绍两个开源项目,然后创建应用最 ...
- 2012年中国移动地图和导航市场研究报告简版
2019独角兽企业重金招聘Python工程师标准>>> 2012年中国移动地图和导航市场研究报告简版 2012年中国移动地图和导航市场用户规模为2.53亿人,增长率为62.2%.伴随 ...
- 10分钟手撸极简版ORM框架!
最近很多小伙伴对ORM框架的实现很感兴趣,不少读者在冰河的微信上问:冰河,你知道ORM框架是如何实现的吗?比如像MyBatis和Hibernte这种ORM框架,它们是如何实现的呢? 为了能够让小伙伴们 ...
- 《数字孪生体技术白皮书(2019)》(简版)全文
来源:<数字孪生体实验室原创> 12月27日,数字孪生体实验室与安世亚太联合正式发布了<数字孪生体技术白皮书(2019)>. 白皮书的第一部分关注对数字孪生体的抽象和总结.无论 ...
- Dockerfile 简版大全,附赠编写实例
基础镜像可以用于创建Docker容器.镜像可以非常基础,仅仅包含操作系统:也可以非常丰富,包含灵巧的应用栈,随时可以发布.当你在使用Docker构建镜像的时候,每一个命令都会在前一个命令的基础上形成一 ...
- react-redux简版实现
Provider组件 Provider用于建立能够被子组件访问的全局属性,核心API有两个: childContextTypes静态属性,用于指定被子组件访问的全局属性类型 getChildConte ...
最新文章
- 【ESP8266】使用ESP8266 NONOS SDK的JSON API
- xml web service
- 日期型转json格式(springboot)
- 万物皆可文本时代来临?如何搞定NLP最强模型GPT
- python 端口扫描
- ecshop分页类assign_pager分析和扩展
- 【CodeForces - 1082B】Vova and Trophies (贪心模拟,暴力)
- mysql-优化班学习-8-20170606-MySQL索引
- 将数组项复制到另一个数组中
- Win10 OPNET14.5+VS2010 安装教程
- 平面方程、夹角与点到平面的距离
- poi合并docx文档
- 有没有无痛无害的人体成像方法?OCT(光学相干断层扫描)了解一下
- Azido-TAT,大环化合物,双功能螯合剂的性质
- 计算机技术与应用论文,计算机应用技术论文
- 显示器购买攻略【小白必看】
- 泛型学习笔记:泛型使用的注意点、泛型在继承方面的体现、自定义泛型结构、泛型应用举例、通配符
- office2010打开excel文档时为空白的解决方法
- Nexus Maven私服配置
- 一个微服务业务系统的中台构建之路
热门文章
- Linux的实际操作:文件目录类的实用指令(cat more less)
- JAVA入门级教学之(对象的使用)
- mysql api 连接池_SpringBoot-整合HikariCP连接池
- 梦幻西游服务器每周几维护,梦幻西游5月6日维护公告:唯美版地图不再更新
- spring 2.0核心技术与最佳实践 pdf_推荐 Spring Boot 实践学习案例大全 数据缓存 和中间件 安全权限...
- 计算机网络中的数据链路层
- leetcode 142 --- linked-list-cycle-ii
- word刷子刷格式_Excel技巧—开始菜单之格式刷六大功能
- mysql 5.1.53_mysql 5.1.53免安装版的优化配备和精简
- linux spi驱动分析 三,Linux下SPI驱动分析