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 相关文章推荐
PHP中的正规表达式(二)
Oct 09 PHP
php下用cookie统计用户访问网页次数的代码
May 09 PHP
超级好用的一个php上传图片类(随机名,缩略图,加水印)
Jun 30 PHP
PHP调用Webservice实例代码
Jul 29 PHP
基于PHP文件操作的详解
Jun 05 PHP
thinkphp控制器调度使用示例
Feb 24 PHP
php获取文件大小的方法
Feb 26 PHP
PHP错误Parse error: syntax error, unexpected end of file in test.php on line 12解决方法
Jun 23 PHP
php面向对象中static静态属性与方法的内存位置分析
Feb 08 PHP
PHP验证终端类型是否为手机的简单实例
Feb 07 PHP
thinkPHP+phpexcel实现excel报表输出功能示例
Jun 06 PHP
php 多进程编程父进程的阻塞与非阻塞实例分析
Feb 22 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
PHP 中执行排序与 MySQL 中排序
2009/04/21 PHP
PHP 第二节 数据类型之转换
2012/04/28 PHP
php动态添加url查询参数的方法
2015/04/14 PHP
php设计模式之原型模式分析【星际争霸游戏案例】
2020/03/23 PHP
JavaScript实际应用:innerHTMl和确认提示的使用
2006/06/22 Javascript
使用apply方法处理数组的三个技巧[译]
2012/09/20 Javascript
jquery实现漂亮的二级下拉菜单代码
2015/08/26 Javascript
js实现商品抛物线加入购物车特效
2020/11/18 Javascript
JS获取鼠标相对位置的方法
2016/09/20 Javascript
对称加密与非对称加密优缺点详解
2017/02/06 Javascript
JS去除字符串中空格的方法
2017/02/14 Javascript
Omi v1.0.2发布正式支持传递javascript表达式
2017/03/21 Javascript
基于jquery实现二级联动效果
2017/03/30 jQuery
微信小程序开发之toast提示插件使用示例
2017/06/08 Javascript
vue页面使用阿里oss上传功能的实例(二)
2017/08/09 Javascript
react redux入门示例
2018/04/19 Javascript
JavaScript闭包原理与用法实例分析
2018/08/10 Javascript
对vue中methods互相调用的方法详解
2018/08/30 Javascript
vue2.0 获取从http接口中获取数据,组件开发,路由配置方式
2019/11/04 Javascript
JavaScript使用canvas绘制随机验证码
2020/02/17 Javascript
[14:00]DOTA2国际邀请赛史上最长大战 赛后专访B神
2013/08/10 DOTA
[01:28:56]2014 DOTA2华西杯精英邀请赛 5 24 CIS VS DK
2014/05/26 DOTA
[34:41]夜魇凡尔赛茶话会 第二期02:你画我猜
2021/03/11 DOTA
python学习手册中的python多态示例代码
2014/01/21 Python
Django 导出 Excel 代码的实例详解
2017/08/11 Python
python3 pillow生成简单验证码图片的示例
2017/09/19 Python
python线程池threadpool实现篇
2018/04/27 Python
python将数组n等分的实例
2019/12/02 Python
Python脚本实现监听服务器的思路代码详解
2020/05/28 Python
html5是什么_动力节点Java学院整理
2017/07/07 HTML / CSS
澳大利亚在线奢侈品时尚零售平台:Azura Runway
2021/01/13 全球购物
地球鞋加拿大官网:Earth Shoes Canada
2020/11/17 全球购物
八一慰问活动方案
2014/02/07 职场文书
奉献家乡演讲稿
2014/09/16 职场文书
调解协议书范本
2016/03/21 职场文书
python使用tkinter实现透明窗体上绘制随机出现的小球(实例代码)
2021/05/17 Python