当前位置:首页 > PHP教程 > php高级应用 > 列表

PHP创建简单RPC服务案例详解

发布:smiling 来源: PHP粉丝网  添加日期:2022-05-13 14:10:24 浏览: 评论:0 

这篇文章主要介绍了PHP创建简单RPC服务案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下。

RPC 定义

RPC(Remote Procedure Call)即远程过程调用,指被调用方法的具体实现不在程序运行本地,而是在别的某个地方。主要应用于不同的系统之间的远程通信和相互调用。

如 A 调用 B 提供的 remoteAdd 方法:

首先A与B之间建立一个TCP连接;

然后A把需要调用的方法名(这里是remoteAdd)以及方法参数(10, 20)序列化成字节流发送出去;

B接受A发送过来的字节流,然后反序列化得到目标方法名,方法参数,接着执行相应的方法调用(可能是localAdd)并把结果30返回;

A接受远程调用结果

有些远程调用选择比较底层的 socket 协议,有些远程调用选择比较上层的 HTTP 协议。

远程调用的好处:

解耦:当方法提供者需要对方法内实现修改时,调用者完全感知不到,不用做任何变更;这种方式在跨部门,跨公司合作的时候经常用到,并且方法的提供者我们通常称为:服务的暴露方

这里使用 PHP Socket 来创建一个服务端和客户端,目录结构如下:

PHP创建简单RPC服务案例详解

服务端

  1. <?php 
  2. class RpcServer { 
  3.     protected $server = null; 
  4.  
  5.     public function __construct($host$port$path
  6.     { 
  7.         // 创建一个 Socket 服务 
  8.         if(($this->server = socket_create(AF_INET,SOCK_STREAM,SOL_TCP)) < 0) { 
  9.             exit("socket_create() 失败的原因是:".socket_strerror($this->server)."\n"); 
  10.         } 
  11.         if(($ret = socket_bind($this->server,$host,$port)) < 0) { 
  12.             exit("socket_bind() 失败的原因是:".socket_strerror($ret)."\n"); 
  13.         } 
  14.         if(($ret = socket_listen($this->server,3)) < 0) { 
  15.             exit("socket_listen() 失败的原因是:".socket_strerror($ret)."\n"); 
  16.         } 
  17.  
  18.         // 判断 RPC 服务目录是否存在 
  19.         $realPath = realpath(__DIR__ . $path); 
  20.         if ($realPath === false || !file_exists($realPath)) { 
  21.             exit("{$path} error \n"); 
  22.         } 
  23.  
  24.         do { 
  25.             $client = socket_accept($this->server); 
  26.             if($client) { 
  27.                 // 一次性读取 
  28.                 $buf = socket_read($client, 8024); 
  29.                 echo $buf
  30.  
  31.                 //解析客户端发送过来的协议 
  32.                 $classRet = preg_match('/Rpc-Class:\s(.*);\r\n/i'$buf$class); 
  33.                 $methodRet = preg_match('/Rpc-Method:\s(.*);\r\n/i'$buf$method); 
  34.                 $paramsRet = preg_match('/Rpc-Params:\s(.*);\r\n/i'$buf$params); 
  35.  
  36.                 if($classRet && $methodRet) { 
  37.                     $class = ucfirst($class[1]); 
  38.                     $method = $method[1]; 
  39.                     $params = json_decode($params[1], true); 
  40.                     $file = $realPath . '/' . $class . '.php';  // 类文件需要和类名一致 
  41.                     $data = ''// 执行结果 
  42.                     // 判断类文件是否存在 
  43.                     if(file_exists($file)) { 
  44.                         // 引入类文件 
  45.                         require_once $file
  46.                         // 实例化类 
  47.                         $rfc_obj = new ReflectionClass($class); 
  48.                         // 判断该类指定方法是否存在 
  49.                         if($rfc_obj->hasMethod($method)) { 
  50.                             // 执行类方法 
  51.                             $rfc_method = $rfc_obj->getMethod($method); 
  52.                             $data = $rfc_method->invokeArgs($rfc_obj->newInstance(), [$params]); 
  53.                         } else { 
  54.                             socket_write($client'method error'); 
  55.                         } 
  56.                         //把运行后的结果返回给客户端 
  57.                         socket_write($client$data); 
  58.                     } 
  59.                 } else { 
  60.                     socket_write($client'class or method error'); 
  61.                 } 
  62.  
  63.                 // 关闭客户端 
  64.                 socket_close($client); 
  65.             } 
  66.  
  67.         }while(true); 
  68.     } 
  69.  
  70.     public function __destruct() 
  71.     { 
  72.         socket_close($this->server); 
  73.     } 
  74.  
  75. new RpcServer('127.0.0.1',8080,'./service'); 

客户端

  1. <?php 
  2. class RpcClient { 
  3.     protected $client = null; 
  4.     protected $url_info = [];   // 远程调用 URL 组成部分 
  5.  
  6.     public function __construct($url
  7.     { 
  8.         // 解析 URL 
  9.         $this->url_info = parse_url($url); 
  10.     } 
  11.  
  12.     public function __call($name$arguments
  13.     { 
  14.         // 创建一个客户端 
  15.         $this->client = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); 
  16.         if(!$this->client) { 
  17.             exit('socket_create() 失败'); 
  18.         } 
  19.         socket_connect($this->client, $this->url_info['host'], $this->url_info['port']); 
  20.  
  21.         // 传递调用的类名 
  22.         $class = basename($this->url_info['path']); 
  23.         // 传递调用的参数 
  24.         $args = ''
  25.         if(isset($arguments[0])) { 
  26.             $args = json_encode($arguments[0]); 
  27.         } 
  28.         // 向服务端发送我们自定义的协议数据 
  29.         $proto = "Rpc-Class: {$class};".PHP_EOL 
  30.             ."Rpc-Method: {$name};".PHP_EOL 
  31.             ."Rpc-Params: {$args};".PHP_EOL; 
  32.         socket_write($this->client, $proto); 
  33.         // 读取服务端传来的数据 
  34.         $buf = socket_read($this->client, 8024); 
  35.         socket_close($this->client); 
  36.         return $buf
  37.     } 
  38.  
  39. $rpcClient = new RpcClient('http://127.0.0.1:8080/news'); 
  40. echo $rpcClient->display(['title'=>'txl']); 
  41. echo $rpcClient->display(['title'=>'hello world']); 

服务类 News

  1. <?php 
  2. class News { 
  3.     public function display($data
  4.     { 
  5.         return json_encode(['result'=>"News display(), title is {$data['title']}"]); 
  6.     } 

运行测试:

Client

PHP创建简单RPC服务案例详解

Server

PHP创建简单RPC服务案例详解

Tags: PHP创建简单RPC服务

分享到: