PHP實現簡單RPC


1.什么是rpc

RPC全稱為Remote Procedure Call,翻譯過來為“遠程過程調用”。目前,主流的平台中都支持各種遠程調用技術,以滿足分布式系統架構中不同的系統之間的遠程通信和相互調用。遠程調用的應用場景極其廣泛,實現的方式也各式各樣。

2.從通信協議的層面

基於HTTP協議的(例如基於文本的SOAP(XML)、Rest(JSON),基於二進制Hessian(Binary))
基於TCP協議的(通常會借助Mina、Netty等高性能網絡框架)

3.從不同的開發語言和平台層面

單種語言或平台特定支持的通信技術(例如Java平台的RMI、.NET平台Remoting)
支持跨平台通信的技術(例如HTTP Rest、Thrift等)

4.從調用過程來看

同步通信調用(同步RPC)
異步通信調用(MQ、異步RPC)

5.常見的幾種通信方式

遠程數據共享(例如:共享遠程文件,共享數據庫等實現不同系統通信)
消息隊列
RPC(遠程過程調用)

6.php實現簡單的rpc

目錄結構


 
image.png


rpc服務端

  1 <?php
  2 /**
  3  * User: yuzhao
  4  * CreateTime: 2018/11/15 下午11:46
  5  * Description: Rpc服務端
  6  */
  7 class RpcServer {
  8 
  9     /**
 10      * User: yuzhao
 11      * CreateTime: 2018/11/15 下午11:51
 12      * @var array
 13      * Description: 此類的基本配置
 14      */
 15     private $params = [
 16         'host'  => '',  // ip地址,列出來的目的是為了友好看出來此變量中存儲的信息
 17         'port'  => '', // 端口
 18         'path'  => '' // 服務目錄
 19     ];
 20 phper在進階的時候總會遇到一些問題和瓶頸,業務代碼寫多了沒有方向感,不知道該從那里入手去提升,對此我整理了一些資料,
包括但不限於:分布式架構、高可擴展、高性能、高並發、服務器性能調優、TP6,
laravel,YII2,Redis,Swoole、Kafka、Mysql優化、shell腳本、Docker、微服務、Nginx等多個知識點高級進階干貨需要的可以免費分享給大家,需要的請點擊(→)我的官方群 21 /** 22 * User: yuzhao 23 * CreateTime: 2018/11/16 上午12:14 24 * @var array 25 * Description: 本類常用配置 26 */ 27 private $config = [ 28 'real_path' => '', 29 'max_size' => 2048 // 最大接收數據大小 30 ]; 31 32 /** 33 * User: yuzhao 34 * CreateTime: 2018/11/15 下午11:50 35 * @var nul 36 * Description: 37 */ 38 private $server = null; 39 40 /** 41 * Rpc constructor. 42 */ 43 public function __construct($params) 44 { 45 $this->check(); 46 $this->init($params); 47 } 48 49 /** 50 * User: yuzhao 51 * CreateTime: 2018/11/16 上午12:0 52 * Description: 必要驗證 53 */ 54 private function check() { 55 $this->serverPath(); 56 } 57 58 /** 59 * User: yuzhao 60 * CreateTime: 2018/11/15 下午11:48 61 * Description: 初始化必要參數 62 */ 63 private function init($params) { 64 // 將傳遞過來的參數初始化 65 $this->params = $params; 66 // 創建tcpsocket服務 67 $this->createServer(); 68 } 69 70 /** 71 * User: yuzhao 72 * CreateTime: 2018/11/16 上午12:0 73 * Description: 創建tcpsocket服務 74 75 */ 76 private function createServer() { 77 $this->server = stream_socket_server("tcp://{$this->params['host']}:{$this->params['port']}", $errno,$errstr); 78 if (!$this->server) exit([ 79 $errno,$errstr 80 ]); 81 } 82 83 /** 84 * User: yuzhao 85 * CreateTime: 2018/11/15 下午11:57 86 * Description: rpc服務目錄 87 */ 88 public function serverPath() { 89 $path = $this->params['path']; 90 $realPath = realpath(__DIR__ . $path); 91 if ($realPath === false ||!file_exists($realPath)) { 92 exit("{$path} error!"); 93 } 94 $this->config['real_path'] = $realPath; 95 } 96 97 /** 98 * User: yuzhao 99 * CreateTime: 2018/11/15 下午11:51 100 * Description: 返回當前對象 101 */ 102 public static function instance($params) { 103 return new RpcServer($params); 104 } 105 106 /** 107 * User: yuzhao 108 * CreateTime: 2018/11/16 上午12:06 109 * Description: 運行 110 */ 111 public function run() { 112 while (true) { 113 $client = stream_socket_accept($this->server); 114 if ($client) { 115 echo "有新連接\n"; 116 $buf = fread($client, $this->config['max_size']); 117 print_r('接收到的原始數據:'.$buf."\n"); 118 // 自定義協議目的是拿到類方法和參數(可改成自己定義的) 119 $this->parseProtocol($buf,$class, $method,$params); 120 // 執行方法 121 $this->execMethod($client, $class, $method, $params); 122 //關閉客戶端 123 fclose($client); 124 echo "關閉了連接\n"; 125 } 126 } 127 } 128 129 /** 130 * User: yuzhao 131 * CreateTime: 2018/11/16 上午12:19 132 * @param $class 133 * @param $method 134 * @param $params 135 * Description: 執行方法 136 */ 137 private function execMethod($client, $class, $method, $params) { 138 if($class && $method) { 139 // 首字母轉為大寫 140 $class = ucfirst($class); 141 $file = $this->params['path'] . '/' . $class . '.php'; 142 //判斷文件是否存在,如果有,則引入文件 143 if(file_exists($file)) { 144 require_once $file; 145 //實例化類,並調用客戶端指定的方法 146 $obj = new $class(); 147 //如果有參數,則傳入指定參數 148 if(!$params) { 149 $data = $obj->$method(); 150 } else { 151 $data = $obj->$method($params); 152 } 153 // 打包數據 154 $this->packProtocol($data); 155 //把運行后的結果返回給客戶端 156 fwrite($client, $data); 157 } 158 } else { 159 fwrite($client, 'class or method error'); 160 } 161 } 162 163 /** 164 * User: yuzhao 165 * CreateTime: 2018/11/16 上午12:10 166 * Description: 解析協議 167 */ 168 private function parseProtocol($buf, &$class, &$method, &$params) { 169 $buf = json_decode($buf, true); 170 $class = $buf['class']; 171 $method = $buf['method']; 172 $params = $buf['params']; 173 } 174 175 /** 176 * User: yuzhao 177 * CreateTime: 2018/11/16 上午12:30 178 * @param $data 179 * Description: 打包協議 180 */ 181 private function packProtocol(&$data) { 182 $data = json_encode($data, JSON_UNESCAPED_UNICODE); 183 } 184 185 } 186 187 RpcServer::instance([ 188 'host' => '127.0.0.1', 189 'port' => 8888, 190 'path' => './api' 191 ])->run();

rpc 客戶端

 1 <?php
 2 /**
 3  * User: yuzhao
 4  * CreateTime: 2018/11/16 上午12:2
 5  * Description: Rpc客戶端
 6  */
 7 class RpcClient {
 8 
 9     /**
10      * User: yuzhao
11      * CreateTime: 2018/11/16 上午12:21
12      * @var array
13      * Description: 調用的地址
14      */
15     private $urlInfo = array();
16 
17     /**
18      * RpcClient constructor.
19      */
20     public function __construct($url)
21     {
22         $this->urlInfo = parse_url($url);
23     }
24 
25     /**
26      * User: yuzhao
27      * CreateTime: 2018/11/16 上午12:2
28      * Description: 返回當前對象
29      */
30     public static function instance($url) {
31         return new RpcClient($url);
32     }
33 
34     public function __call($name, $arguments)
35     {
36         // TODO: Implement __call() method.
37         //創建一個客戶端
38         $client = stream_socket_client("tcp://{$this->urlInfo['host']}:{$this->urlInfo['port']}", $errno, $errstr);
39         if (!$client) {
40             exit("{$errno} : {$errstr} \n");
41         }
42         $data = [
43             'class'  => basename($this->urlInfo['path']),
44             'method' => $name,
45             'params' => $arguments
46         ];
47         //向服務端發送我們自定義的協議數據
48         fwrite($client, json_encode($data));
49         //讀取服務端傳來的數據
50         $data = fread($client, 2048);
51         //關閉客戶端
52         fclose($client);
53         return $data;
54     }
55 }
56 $cli = new RpcClient('http://127.0.0.1:8888/test');
57 echo $cli->tuzisir1()."\n";
58 echo $cli->tuzisir2(array('name' => 'tuzisir', 'age' => 23));

提供服務的文件

 1 <?php
 2 /**
 3  * User: yuzhao
 4  * CreateTime: 2018/11/16 上午12:28
 5  * Description:
 6  */
 7 
 8 class Test {
 9 
10     public function tuzisir1() {
11         return '我是無參方法';
12     }
13     public function tuzisir2($params) {
14         return $params;
15     }
16 }

效果

 

 

image.png

7.RPC的注意事項

性能:影響RPC性能的主要在幾個方面:
1.序列化/反序列化的框架
2.網絡協議,網絡模型,線程模型等

安全
RPC安全的主要在於服務接口的鑒權和訪問控制支持。

跨平台
跨不同的操作系統,不同的編程語言和平台。

 
 
 
 
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM