博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
RPC 简单小试
阅读量:4343 次
发布时间:2019-06-07

本文共 3755 字,大约阅读时间需要 12 分钟。

 由于经常被抓取文章内容,在此附上博客文章网址:,偶尔会更新某些出错的数据或文字,建议到我博客地址 :  --> 

  RPC是指远程过程调用,也就是说两台服务器A,B,一个应用部署在A服务器上,想要调用B服务器上应用提供的函数/方法,由于不在一个内存空间,不能直接调用,需要通过网络来表达调用的语义和传达调用的数据。

百度中有很多种解释,但根据公司所用的,以下解释比较贴切:
        首先,要解决通讯的问题,主要是通过在客户端和服务器之间建立TCP连接,远程过程调用的所有交换的数据都在这个连接里传输。连接可以是按需连接,调用结束后就断掉,也可以是长连接,多个远程过程调用共享同一个连接。
        第二,要解决寻址的问题,也就是说,A服务器上的应用怎么告诉底层的RPC框架,如何连接到B服务器(如主机或IP地址)以及特定的端口,方法的名称名称是什么,这样才能完成调用。比如基于Web服务协议栈的RPC,就要提供一个endpoint URI,或者是从UDDI服务上查找。如果是RMI调用的话,还需要一个RMI Registry来注册服务的地址。
        第三,当A服务器上的应用发起远程过程调用时,方法的参数需要通过底层的网络协议如TCP传递到B服务器,由于网络协议是基于二进制的,内存中的参数的值要序列化成二进制的形式,也就是序列化(Serialize)或编组(marshal),通过寻址和传输将序列化的二进制发送给B服务器。
        第四,B服务器收到请求后,需要对参数进行反序列化(序列化的逆操作),恢复为内存中的表达方式,然后找到对应的方法(寻址的一部分)进行本地调用,然后得到返回值。
        第五,返回值还要发送回服务器A上的应用,也要经过序列化的方式发送,服务器A接到后,再反序列化,恢复为内存中的表达方式,交给A服务器上的应用

公司所用的是客户端为php,服务端为lua。


举例(只是两个简单的示例,实际项目比较复杂):

服务端示例:

serv = stream_socket_server("tcp://{$host}:{$port}", $errno, $errstr); if (!$this->serv) { exit("one {$errno} : {$errstr} \n"); } //判断我们的RPC服务目录是否存在 $realPath = realpath(__DIR__ . $path); if ($realPath === false || !file_exists($realPath)) { exit("two {$path} error \n"); } while (true) { $client = stream_socket_accept($this->serv); if ($client) { //这里为了简单,我们一次性读取 $buf = fread($client, 2048); //解析客户端发送过来的协议 $classRet = preg_match('/Rpc-Class:\s(.*);\r\n/i', $buf, $class); $methodRet = preg_match('/Rpc-Method:\s(.*);\r\n/i', $buf, $method); $paramsRet = preg_match('/Rpc-Params:\s(.*);\r\n/i', $buf, $params); if($classRet && $methodRet) { $class = ucfirst($class[1]); $file = $realPath . '/' . $class . '.php'; //判断文件是否存在,如果有,则引入文件 if(file_exists($file)) { require_once $file; //实例化类,并调用客户端指定的方法 $obj = new $class(); //如果有参数,则传入指定参数 if(!$paramsRet) { $data = $obj->$method[1](); } else { $data = $obj->$method[1](json_decode($params[1], true)); } //把运行后的结果返回给客户端 fwrite($client, $data); } } else { fwrite($client, 'class or method error' . $classRet . '-' . $methodRet); } //关闭客户端 fclose($client); } } } public function __destruct() { fclose($this->serv); }} new RpcServer('127.0.0.1', 8888, '/service');

客户端举例:

urlInfo = parse_url($url); if(!$this->urlInfo) { exit("{$url} error \n"); } } public function __call($method, $params) { //创建一个客户端 $client = stream_socket_client("tcp://{$this->urlInfo['host']}:{$this->urlInfo['port']}", $errno, $errstr); if (!$client) { exit("{$errno} : {$errstr} \n"); } //传递调用的类名 $class = basename($this->urlInfo['path']); $proto = "Rpc-Class: {$class};" . 'Say'; //传递调用的方法名 $proto .= "Rpc-Method: {$method};" . 'hello'; //传递方法的参数 $params = json_encode($params); $proto .= "Rpc-Params: {$params};" . PHP_EOL; //向服务端发送我们自定义的协议数据 fwrite($client, $proto); //读取服务端传来的数据 $data = fread($client, 2048); //关闭客户端 fclose($client); return $data; }} $cli = new RpcClient('http://127.0.0.1:8888/test');echo $cli->hehe();echo $cli->hehe2(array('name' => 'test', 'age' => 27));

 先启动服务端,再启动客户端

 

 

转载于:https://www.cnblogs.com/zhenghongxin/p/7483267.html

你可能感兴趣的文章
总结五个在办公中使用很爽的软件
查看>>
使用对象属性
查看>>
PWM输出,呼吸灯
查看>>
QTcpSocket发送结构体
查看>>
redmine install 菜鸟的艰难历程
查看>>
总结2:指出代码中的错误
查看>>
[唐胡璐]Selenium技巧- 抓图并保存到TestNG报告中
查看>>
P1352 没有上司的舞会
查看>>
图像特征提取:Sobel边缘检测
查看>>
java面试题及答案
查看>>
通过 SysVinit、Systemd 和 Upstart 管理系统自启动进程和服务
查看>>
学习进度条
查看>>
搞懂 SynchronizationContext(第一部分)【翻译】
查看>>
常用的nginx rewrite重写规则
查看>>
[转]PHP正则表达式
查看>>
mybatis 嵌套查询与懒加载
查看>>
Vm workstation安装win8 的问题
查看>>
one list to muti list
查看>>
Regular Expression Patterns
查看>>
在 Linux 下使用 水星MW150cus (RTL8188CUS芯片)无线网卡
查看>>