我对RPC的理解

1、简介

  这篇文章将会用最直白的方式介绍RPC,以及实现RPC客户端的Ajax跨域调用的例子。

  RPC(Remote Procedure Call Protocol)--远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发包括网络分布式多程序在内的应用程序更加容易。

  RPC采用客户机/服务器模式。请求程序就是一个客户机,而服务提供程序就是一个服务器。首先,客户机调用进程发送一个有进程参数的调用信息到服务进程,然后等待应答信息。在服务器端,进程保持睡眠状态直到调用信息的到达为止。当一个调用信息到达,服务器获得进程参数,计算结果,发送答复信息,然后等待下一个调用信息,最后,客户端调用进程接收答复信息,获得进程结果,然后调用执行继续进行。

以上来自度娘!看完上面明白什么是RPC么,在心中能将RPC整个服务过程构造出来么?当然不能啦,对于我们这种小白来说最好是用最直白的语言进行描述。

  从字面上我们是大概了解到是从一个服务器中调用另一个服务器中的方法,使用它提供的功能。在我最开始接触RPC的时候,是在这本书中《PHP精粹:编写高效PHP代码》【(美)Lorna Mitchell,(美)Davey Shafik,(美)Matthew Turland著;彭冲,胡琳译】。是的,我所从事的语言就是世界上最好的语言--PHP,222333哈哈。

  在这本书中所介绍的RPC的实现方式是通过HTTP协议进行的。但是当我在寻找相关资料的时候,已看其他语言的例子,咋不一样的咧,难道PHP就是独特的?RPC即是远程调用,一般来说是不关语言层面的呀!

  的确,RPC=Remote Produce Call 是一种技术的概念名词它可以通过不同的方式实现。http是rpc实现的一种方式,RPC还可以通过Socket自己实现一套协议来实现。当然啦,不同的实现方式有不同的特点,长短连接、数据的传输方式、灵活性等等。

  RPC的核心并不在于使用什么协议。RPC的目的是让你在本地调用远程的方法,而对你来说这个调用是透明的,你并不知道这个调用的方法是部署哪里。通过RPC能解耦服务,这才是使用RPC的真正目的。

RPC(远程过程调用)是什么

  • 简单的说,RPC就是从一台机器(客户端)上通过参数传递的方式调用另一台机器(服务器)上的一个函数或方法(可以统称为服务)并得到返回的结果。
  • RPC 会隐藏底层的通讯细节(不需要直接处理Socket通讯或Http通讯)
  • RPC 是一个请求响应模型。客户端发起请求,服务器返回响应(类似于Http的工作方式)
  • RPC 在使用形式上像调用本地函数(或方法)一样去调用远程的函数(或方法)

即能够调用远程规定好的接口就可称之为RPC!在我上一篇文章中所讲的Web service(SOAP)也是RPC的一种实现方式。

  Thrift ,这是我最近学习的一个RPC框架,它很强大,数据是通过二进制格式进行传输,相对 XML 和 JSON 体积更小,对于高并发、大数据量和多语言的环境更有优势。当然啦,这里不讲这个RPC框架,毕竟刚接触,对于Thrift这方面的知识还是菜鸟级别。能懂一丢丢但是距离将它写成博客文章还是差很远的。

  接下来我将采用HTTP方式来实现一个RPC,并且在客户端中能够在Ajax下进行跨域访问。

2、PRC实例

  环境介绍:www.test88.com作为服务主机、www.test99.com作为客户端主机

  一个好的api可以支持不同的格式输出、大多RPC采用post方式提交数据!接下来我们将采用json格式输出、POST提交数据

  2.1、先建立具体服务功能的逻辑程序

  WebServer.class.php【www.test88.com】

 1 <?php
 2 class WebServer
 3 {
 4     public static function test($name,$age,$action)
 5     {
 6         return $name.',今年年龄'.$age.',最喜欢做的事情是'.$action;
 7     }
 8     public static function look()
 9     {
10         return $_POST;
11     }
12     public static function nono()
13     {
14         return '啥鸡毛都没有';
15     }
16 }
17 ?>

  2.2、服务端提供相应的入口

  WebServer.php【www.test88.com】

  返回数据使用json格式!一个最基本的RPC服务已经建成!

 1 <?php
 2 require './WebServer.class.php';
 3 if(isset($_POST['method']))
 4 {
 5     $post=$_POST;
 6     switch ($_POST['method']) {
 7         case 'test':
 8             $respond=WebServer::test($post['name'],$post['age'],$post['action']);
 9             break;
10         case 'look':
11             $respond=WebServer::look();
12             break;
13         default:
14             $respond=WebServer::nono();
15             break;
16     }
17 }
18 else
19 {
20     $respond='木有!';
21 }
22 header('content-type:application/json');
23 echo json_encode($respond);
24 #echo $respond;
25 ?>

  2.3、建立跨域代理脚本

  跨域请求解决:为避免同源策略,可使用服务器端代理即写个代理脚本放入自己的域中,使用ajax来访问代理脚本,脚本远程访问api接收数据,再将数据返回给需要的地方(好处:可是在代理的时候将接收回来的数据进行相应的数据类型结构处理,再返回需要的地方)

  Agency.class.php【www.test99.com】

 1 <?php
 2 class Agency
 3 {
 4     #允许访问的api域名、返回的数据类型
 5     public $allowHost=array('test88.com'=>array('mimetype'=>'aplication/json'));
 6     public $host='';
 7 
 8     public function __construct()
 9     {
10         $this->host=parse_url("http:/".$_SERVER['PATH_INFO'],PHP_URL_HOST); #提取域名参数
11     }
12 
13     /**
14     * @desc 设置允许去访问的主机域名
15     *
16     * @param $host   string 域名
17     * @param $array  array  数组,放回的数据类型
18     */    
19     public function setAllowHost($host, $array=array('mimetype'=>'aplication/json'))
20     {
21         $this->allowHost[$host]=$array;
22     }
23 
24     /**
25     * @desc 判断域名
26     *
27     * @param $host string 域名
28     */
29     private function decide($host)
30     {
31         if(!isset($this->allowHost[$host])) #判断host是否允许代理访问
32         {
33             header("Status:403 Forbidden");
34             exit;
35         }
36         return true;
37     }
38 
39     public function requestPost()
40     {
41         $host=$this->host;
42         $this->decide($host);   #判断
43         $host='www.'.$host;  //拼接host
44         $uri=strrchr($_SERVER['PATH_INFO'],'/'); #提取具体URI
45         $port=80;
46         $link=fsockopen($host,$port);
47         //请求行
48         #$request_data="POST /WebServer.php HTTP/1.1\r\n";
49         $request_data="POST $uri HTTP/1.1\r\n";
50         //请求头
51         #$request_data.="Host: www.test88.com\r\n";
52         $request_data.="Host: $host\r\n";
53         $request_data.="User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64; rv:10.0) Gecko/20100101 Firefox/10.0\r\n";
54         $request_data.="Connection: keep-alive\r\n";
55         #post数据
56         #$post_data=array('name'=>$_POST['name'],'ff'=>'bbb');
57         $post_content=http_build_query($_POST);
58         $len=strlen($post_content);
59         $request_data.="Content-Length: ".$len."\r\n";
60         $request_data.="Content-Type: application/x-www-form-urlencoded\r\n";
61         
62         $request_data.="\r\n"; //空行表示头结束
63         
64         //请求主体
65         $request_data.=$post_content;
66         
67         //发送数据
68         fwrite($link,$request_data);
69         
70         //接收数据
71         $inheader=1;
72         while(!feof($link))
73         {
74             #echo fgets($link,1024);
75             //除去请求头,只显示返回数据
76             $data=fgets($link,1024);
77             if($inheader && ($data=="\n" || $data=="\r\n"))
78             {
79                 $inheader=0;
80             }
81             if($inheader==0)
82             {
83                 var_dump(json_decode($data));
84                 echo ($data);  #用于测试
85             }
86         }
87         //关闭请求
88         fclose($link);
89     }
90 
91 
92 }

  实例化脚本:agency.php【www.test99.com】

1 <?php
2 include "./Agency.class.php";
3 $a=new Agency();
4 $a->requestPost();
5 ?>

  2.4、Ajax访问

  建立相应的html文件

  button.html【www.test99.com】

 1 <!DOCTYPE html>
 2 <html>
 3 <head>
 4     <meta charset="utf-8">
 5     <title>button</title>
 6 </head>
 7 <body>
 8 <button id='b1'>按钮1</button>
 9 </body>
10 <script type="text/javascript">
11 var b1=document.getElementById('b1');
12 b1.onclick=function()
13 {
14     var xhr=new XMLHttpRequest();
15     xhr.onreadystatechange=function()
16     {
17         if(xhr.readyState==4)
18         {
19             //document.body.innerHTML+=xhr.responseText;
20             alert(xhr.responseText)
21         }
22     }
23     //代理文件+(需要访问的api的域名+api具体的某个接口)
24     xhr.open('post','./agency.php/test88.com/WebServer.php');   
25         xhr.setRequestHeader('content-type','application/x-www-form-urlencoded');
26         //api接口参数使用info来传递
27         var info='method=look&name=小明&age=20&action=打架';   //相应参数
28         xhr.send(info);
29 }
30 </script>
31 </html>

  2.5、开始测试

  访问www.test99.com/button.html

  并点击按钮1

  更改访问方法method=test,继续访问

大功告成!

3、总结

  总的来说,我所写的这个例子是非常非常简单的,仅仅只是用来参考哈。当然啦,性能上肯定是鸡肋。在我自己做简单测试的时候,Ajax刷新返回数据都非常缓慢。对于小白的我们来说,结合一个简单实用的例子来学习了解一门技术还是不错的!希望大家对RPC的学习不要止步于此哈,毕竟我这篇博客是入门级的,更多相关的RPC知识还等着大家去挖掘呢!

(以上是自己的一些见解,若有不足或者错误的地方请各位指出)

 作者:那一叶随风 http://www.cnblogs.com/phpstudy2015-6/

 原文地址:http://www.cnblogs.com/phpstudy2015-6/p/6850658.html 

 声明:本博客文章为原创,只代表本人在工作学习中某一时间内总结的观点或结论。转载时请在文章页面明显位置给出原文链接

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏张戈的专栏

解决启用WP-Super-Cache后出现的几个问题

近期,随着新版互推联盟自适应 iframe 代码的推出,调用的博友也慢慢增加了 ,这是很高兴的事情,也有博友反应调用的这个页面加载会有点慢。我来说明一下,因为这...

43560
来自专栏我的小碗汤

LAMP环境部署物联网项目

物联网,即Internet of Things,简写IOT。让所有能行使独立功能的普通物体实现互联互通的网络,通过物联网可以用中心计算机对机器、设备、人员进行集...

56720
来自专栏智能合约

crontab定时任务详解

30840
来自专栏PHP在线

在Mac下使用MAMP Pro环境

以前,我使用Windows作为自己的工作系统,后来,改用Mac作为自己的主要工作系统了。 在Windows下,快速搭建*AMP环境,使用xampp或者WAMP之...

80470
来自专栏FreeBuf

史上最全Linux提权后获取敏感信息方法

在本文开始之前,我想指出我不是专家。据我所知,在这个庞大的区域,没有一个“神奇”的答案。下面是一个混合的命令做同样的事情,在不同的地方,或只是一个不同的眼光来看...

84260
来自专栏杨建荣的学习笔记

Datapump数据迁移前的准备工作(r9笔记第31天)

其实对于Datapump迁移而言,如果参与过XTTS,OGG,Veritas SF,外部表增量等迁移方式的话,会发现Datapump还是很简单清晰的,一个优点...

28230
来自专栏玄魂工作室

​ kali linux 渗透测试 之 DNS信息收集

从本节开始,我们从头开始,系统的学习基于Kali Linux的web应用渗透测试。

31530
来自专栏北京马哥教育

Python开源项目介绍:用zmail简单地发邮件

转载自:Python中文社区 ID:python-china 发送邮件是个很简单的需求,但是在实际的使用中依然碰到了很多坑,因此创建了zmail这个项目...

29160
来自专栏IMWeb前端团队

fis3 新特性应用

本文作者:IMWeb 黎清龙 原文出处:IMWeb社区 未经同意,禁止转载 fis3 新特性应用 1 前言 fis3相比fis2,核心思路并没有改变 ...

23390
来自专栏FreeBuf

CVE-2017-4918:VMware Horizon的macOS客户端代码注入漏洞分析

本文我们将探讨如何通过 VMware Horizon macOS客户端版本4.4.0 (5164329)中存在的代码注入漏洞获取本地root权限。在此文发布前我...

27730

扫码关注云+社区

领取腾讯云代金券