1.什麼是rpc RPC全稱為Remote Procedure Call,翻譯過來為“遠程過程調用”。目前,主流的平臺中都支持各種遠程調用技術,以滿足分散式系統架構中不同的系統之間的遠程通信和相互調用。遠程調用的應用場景極其廣泛,實現的方式也各式各樣。 2.從通信協議的層面 基於HTTP協議的(例如 ...
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 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 }
效果
你是否有這樣的煩惱,想學習高級技術,缺乏好的高級學習資料,11年架構師授課的TP5、laravel、swoole、swoft、高併發、分散式等資料,官方群:677079770 ,大牛帶你裝比帶你飛
image.png
7.RPC的註意事項
性能:影響RPC性能的主要在幾個方面:
1.序列化/反序列化的框架
2.網路協議,網路模型,線程模型等
安全
RPC安全的主要在於服務介面的鑒權和訪問控制支持。
跨平臺
跨不同的操作系統,不同的編程語言和平臺。
你是否有這樣的煩惱,想學習高級技術,缺乏好的高級學習資料,11年架構師授課的TP5、laravel、swoole、swoft、高併發、分散式等資料,官方群:677079770 ,大牛帶你裝比帶你飛
推薦閱讀: 一:關於PHP在企業級開發領域的訪談 二:淺談 PHP 與手機 APP 開發(API 介面開發) 三:比RBAC更好的許可權認證方式(Auth類認證) 四:2019年PHP面試題附答案(實戰經驗)