PHP建立簡單RPC服務案例詳解
阿新 • • 發佈:2021-09-07
RPC 定義
RPC(Remote Procedure Call)即遠端過程呼叫,指被呼叫方法的具體實現不在程式執行本地,而是在別的某個地方。主要應用於不同的系統之間的遠端通訊和相互呼叫。
如 A 呼叫 B 提供的 remoteAdd 方法:
- 首先A與B之間建立一個TCP連線;
- 然後A把需要呼叫的方法名(這裡是remoteAdd)以及方法引數(10, 20)序列化成位元組流傳送出去;
- B接受A傳送過來的位元組流,然後反序列化得到目標方法名,方法引數,接著執行相應的方法呼叫(可能是localAdd)並把結果30返回;
- A接受遠端呼叫結果
有些遠端呼叫選擇比較底層的 socket 協議,有些遠端呼叫選擇比較上層的 HTTP 協議。
遠端呼叫的好處:
- 解耦:當方法提供者需要對方法內實現修改時,呼叫者完全感知不到,不用做任何變更;這種方式在跨部門,跨公司合作的時候經常用到,並且方法的提供者我們通常稱為:服務的暴露方
這裡使用 Socket 來建立一個服務端和客戶端,目錄結構如下:
服務端
<?php class RpcServer { protected $server = null; public function www.cppcns.com__construct($host,$port,$path) { // 建立一個 Socket 服務 if(($this->server = socket_create(AF_INET,SOCK_STREAM,SOL_TCP)) < 0) { exit("socket_create() 失敗的原因是:".socket_strerror($this->server)."\n"); } if(($ret = socket_bind($this->server,$host,$port)) < 0) { exit("socket_bind() 失敗的原因是:".socket_strerror($ret)."\n"); } if(($ret = socket_listen($this->server,3)) < 0) { exit("socket_listen() 失敗的原因是:".socket_strerror($ret)."\n"); } // 判斷 RPC 服務目錄是否存在 $realPath = realpath(__DIR__ . $path); if ($realPath === false || !file_exists($realPath)) { exit("{$path} error \n"); } do { $client = socket_accept($this->server); if($client) { // 一次性讀取 $buf = socket_read($client,8024); echo $buf; //解析客戶端傳送過來的協議 $classRet = preg_match('/Rpc-Class:\s(.*);\r\n/i',$buf,$class); $methodRet = preg_match('/Rpc-Method:\s(.*);\r\n/i',$method); $paramsRet = preg_match('/Rpc-Params:\s(.*);\r\n/i',$params); if($classRet && $methodRet) { $class = ucfirst($class[1]); $method = $method[1]; $params = on_decode($params[1],true); $file = $realPath . '/' . $class . '.php'; // 類檔案需要和類名一致 $data = ''; // 執行結果 // 判斷類檔案是否存在 if(file_exists($file)) { // 引入類檔案 require_once $file; // 例項化類 $rfc_obj = new ReflectionClass($class); http://www.cppcns.com// 判斷該類指定方法是否存在 if($rfc_obj->hasMethod($method)) { // 執行類方法 $rfc_method = $rfc_obj->getMethod($method); $data = $rfc_method->invokeArgs($rfc_obj->newInstance(),[$params]); } else { socket_write($client,'method error'); } //把執行後的結果返回給客戶端 socket_write($client,$data); } } else { socket_write($client,'class or method error'); } // 關閉客戶端 socket_close($client); } }while(true); } public function __destruct() { socket_close($this->server); } } new RpcServer('127.0.0.1',8080,'./service');
客戶端
<?php class RpcClient { protected $client = null; protected $url_info = []; // 遠端呼叫 URL 組成部分 public function __construct($url) { // 解析 URL $this->url_info = parse_url($url); } public function __call($name,$arguments) { // 建立一個客戶端 $this->client = socket_create(AF_INET,SOL_TCP); if(!$this->client) { exit('socket_create() 失敗'); } socket_connect($this->client,$this->url_info['host'],$this->url_info['port']); // 傳遞呼叫的類名 $class = basename($this->url_info['path']); // 傳遞呼叫的引數 $args = ''; if(isset($arguments[0])) { $args = json_encode($arguments[0]); } // 向服務端傳送我們自定義的協議資料 $proto = "Rpc-Class: {$class};".PHP_EOL ."Rpc-Method: {$name};".PHP_EOL ."Rpc-Params: {$args};".PHP_EOL; socket_write($this->client,$proto); // 讀取服務端傳來的資料 $buf = socket_read($this->client,8024); socket_close($this->client); return $buf; } } $rpcClient = new RpcClient('http://127.0.0.1:8080/news'); echo $rpcClient->display(['title'=>'txl']); echo $rpcClient->display(['title'=>'hello world']);
服務類 News
<?php class News { public function display($data) { return jsjGDhyGZIhOon_encode(['result'=>"News display(),title is {$data['title']}"]); } }
執行測試:
Client
Server
到此這篇關於PHP建立簡單RPC服務案例詳解的文章就介紹到這了,更多相關PHP建立簡單RPC服務內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!