PHP实现创建一个RPC服务操作示例


Posted in PHP onFebruary 23, 2020

本文实例讲述了PHP实现创建一个RPC服务操作。分享给大家供大家参考,具体如下:

RPC全称为Remote Procedure Call,翻译过来为"远程过程调用"。主要应用于不同的系统之间的远程通信和相互调用。

比如有两个系统,一个是PHP写的,一个是JAVA写的,而PHP想要调用JAVA中的某个类的某个方法,这时候就需要用到RPC了。

怎么调?直接调是不可能,只能是PHP通过某种自定义协议请求JAVA的服务,JAVA解析该协议,在本地实例化类并调用方法,然后把结果返回给PHP。

这里我们用PHP的socket扩展来创建一个服务端和客户端,演示调用过程。

RpcServer.php代码如下:

<?php
class RpcServer {
  protected $serv = null;

  public function __construct($host, $port, $path) {
    //创建一个tcp socket服务
    $this->serv = stream_socket_server("tcp://{$host}:{$port}", $errno, $errstr);
    if (!$this->serv) {
      exit("{$errno} : {$errstr} \n");
    }
    //判断我们的RPC服务目录是否存在
    $realPath = realpath(__DIR__ . $path);
    if ($realPath === false || !file_exists($realPath)) {
      exit("{$path} error \n");
    }

    while (true) {
      $client = stream_socket_accept($this->serv);

      if ($client) {
        //这里为了简单,我们一次性读取
        $buf = fread($client, 2048);
        //解析客户端发送过来的协议
        $classRet = preg_match('/Rpc-Class:\s(.*);\r\n/i', $buf, $class);
        $methodRet = preg_match('/Rpc-Method:\s(.*);\r\n/i', $buf, $method);
        $paramsRet = preg_match('/Rpc-Params:\s(.*);\r\n/i', $buf, $params);
        
        if($classRet && $methodRet) {
          $class = ucfirst($class[1]);
          $file = $realPath . '/' . $class . '.php';
          //判断文件是否存在,如果有,则引入文件
          if(file_exists($file)) {
            require_once $file;
            //实例化类,并调用客户端指定的方法
            $obj = new $class();
            //如果有参数,则传入指定参数
            if(!$paramsRet) {
              $data = $obj->$method[1]();
            } else {
              $data = $obj->$method[1](json_decode($params[1], true));
            }
            //把运行后的结果返回给客户端
            fwrite($client, $data);
          }
        } else {
          fwrite($client, 'class or method error');
        }
        //关闭客户端
        fclose($client);
      }
    }
  }

  public function __destruct() {
    fclose($this->serv);
  }
}

new RpcServer('127.0.0.1', 8888, './service');

RpcClient.php代码如下:

<?php

class RpcClient {
  protected $urlInfo = array();
  
  public function __construct($url) {
    //解析URL
    $this->urlInfo = parse_url($url);
    if(!$this->urlInfo) {
      exit("{$url} error \n");
    }
  }
  
  public function __call($method, $params) {
    //创建一个客户端
    $client = stream_socket_client("tcp://{$this->urlInfo['host']}:{$this->urlInfo['port']}", $errno, $errstr);
    if (!$client) {
      exit("{$errno} : {$errstr} \n");
    }
    //传递调用的类名
    $class = basename($this->urlInfo['path']);
    $proto = "Rpc-Class: {$class};" . PHP_EOL;
    //传递调用的方法名
    $proto .= "Rpc-Method: {$method};" . PHP_EOL;
    //传递方法的参数
    $params = json_encode($params);
    $proto .= "Rpc-Params: {$params};" . PHP_EOL;
    //向服务端发送我们自定义的协议数据
    fwrite($client, $proto);
    //读取服务端传来的数据
    $data = fread($client, 2048);
    //关闭客户端
    fclose($client);
    return $data;
  }
}

$cli = new RpcClient('http://127.0.0.1:8888/test');
echo $cli->hehe();
echo $cli->hehe2(array('name' => 'test', 'age' => 27));

然后分别运行上面两个脚本(注意,php要添加环境变量)

> php RpcServer.php
> php RpcClient.php

结果如下:

PHP实现创建一个RPC服务操作示例

PHP实现创建一个RPC服务操作示例

Test.php代码如下:

<?php
class Test {
  public function hehe() {
    return 'hehe';
  }
  public function hehe2($params) {
    return json_encode($params);
  }
}

目录结构如下:

PHP实现创建一个RPC服务操作示例

上面我们自定义的协议,可以随意修改,只要是客户端和服务端两边能够统一并能解析。

客户端通过请求服务端,把要调用的类,方法和参数传递给服务端,服务端去通过实例化调用方法返回结果。

希望本文所述对大家PHP程序设计有所帮助。

PHP 相关文章推荐
为php4加入动态flash文件的生成的支持
Oct 09 PHP
PHP 高手之路(二)
Oct 09 PHP
PHP编码转换
Nov 05 PHP
PHP迭代器实现斐波纳契数列的函数
Nov 12 PHP
php session劫持和防范的方法
Nov 12 PHP
thinkphp视图模型查询提示ERR: 1146:Table 'db.pr_order_view' doesn't exist的解决方法
Oct 30 PHP
javascript数组与php数组的地址传递及值传递用法实例
Jan 22 PHP
PHP面向对象详解(三)
Dec 07 PHP
Thinkphp实现短信验证注册功能
Oct 18 PHP
php UNIX时间戳用法详解
Feb 16 PHP
Laravel接收前端ajax传来的数据的实例代码
Jul 20 PHP
PHP如何获取Cookie并实现模拟登录
Jul 16 PHP
php 使用ActiveMQ发送消息,与处理消息操作示例
Feb 23 #PHP
php实现通过stomp协议连接ActiveMQ操作示例
Feb 23 #PHP
php ActiveMQ的安装与使用方法图文教程
Feb 23 #PHP
php 多进程编程父进程的阻塞与非阻塞实例分析
Feb 22 #PHP
php7 图形用户界面GUI 开发示例
Feb 22 #PHP
PHP Beanstalkd消息队列的安装与使用方法实例详解
Feb 21 #PHP
PHP pthreads v3在centos7平台下的安装与配置操作方法
Feb 21 #PHP
You might like
第六节--访问属性和方法
2006/11/16 PHP
用PHP解决的一个栈的面试题
2014/07/02 PHP
多个Laravel项目如何共用migrations详解
2018/09/25 PHP
laravel框架添加数据,显示数据,返回成功值的方法
2019/10/11 PHP
php7 图形用户界面GUI 开发示例
2020/02/22 PHP
php实现简易计算器
2020/08/28 PHP
BOOM vs RR BO5 第二场 2.14
2021/03/10 DOTA
js中indexof的用法详细解析
2013/12/24 Javascript
js格式化时间和js格式化时间戳示例
2014/02/10 Javascript
js addDqmForPP给标签内属性值加上双引号的函数
2016/12/24 Javascript
vue页面离开后执行函数的实例
2018/03/13 Javascript
利用d3.js力导布局绘制资源拓扑图实例教程
2019/01/08 Javascript
JS实现星星海特效
2019/12/24 Javascript
Vue中正确使用Element-UI组件的方法实例
2020/10/13 Javascript
JavaScript实现图片合成下载的示例
2020/11/19 Javascript
Python(Tornado)模拟登录小米抢手机
2013/11/12 Python
利用python求解物理学中的双弹簧质能系统详解
2017/09/29 Python
Python实现基于TCP UDP协议的IPv4 IPv6模式客户端和服务端功能示例
2018/03/22 Python
Flask框架配置与调试操作示例
2018/07/23 Python
Python开发虚拟环境使用virtualenvwrapper的搭建步骤教程图解
2018/09/19 Python
Django工程的分层结构详解
2019/07/18 Python
python 3.6.7实现端口扫描器
2019/09/04 Python
Django通过dwebsocket实现websocket的例子
2019/11/15 Python
Pytorch之保存读取模型实例
2019/12/30 Python
解决ROC曲线画出来只有一个点的问题
2020/02/28 Python
Python图片处理模块PIL操作方法(pillow)
2020/04/07 Python
Spark处理数据排序问题如何避免OOM
2020/05/21 Python
CSS3实现银灰色动画效果的导航菜单代码
2015/09/01 HTML / CSS
FORZIERI澳大利亚站:全球顶级奢华配饰精品店
2016/12/31 全球购物
澳洲CFL商城:CHEMIST FOR LESS(中文)
2021/02/28 全球购物
毕业生就业协议书
2014/04/11 职场文书
一帮一活动总结
2014/05/08 职场文书
关于奉献的演讲稿
2014/05/21 职场文书
1000字打架检讨书
2014/11/03 职场文书
个人催款函范文
2015/06/23 职场文书
行政复议答复书
2015/07/01 职场文书