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 相关文章推荐
屏蔽浏览器缓存另类方法
Oct 09 PHP
自动把纯文本转换成Web页面的php代码
Aug 27 PHP
php self,$this,const,static,-&amp;gt;的使用
Oct 22 PHP
适用于php-5.2 的 php.ini 中文版[金步国翻译]
Apr 17 PHP
PHP导入Excel到MySQL的方法
Apr 23 PHP
php使用mb_check_encoding检查字符串在指定的编码里是否有效
Nov 07 PHP
thinkphp项目部署到Linux服务器上报错“模板不存在”如何解决
Apr 27 PHP
PHP实现简易blog的制作
Oct 24 PHP
PHP多进程编程之僵尸进程问题的理解
Oct 15 PHP
thinkphp框架类库扩展操作示例
Nov 26 PHP
PHP的new static和new self的区别与使用
Nov 27 PHP
gearman管理工具GearmanManager的安装与php使用方法示例
Feb 27 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中cookie的作用域
2008/03/27 PHP
javascript温习的一些笔记 基础常用知识小结
2011/06/22 Javascript
js中的scroll和offset 使用比较的实例与分析
2013/09/29 Javascript
javaScript对文字按照拼音排序实现代码
2013/12/27 Javascript
JS将所有对象s的属性复制给对象r(原生js+jquery)
2014/01/25 Javascript
Jquery实现点击按钮,连续地向textarea中添加值的实例代码
2014/03/08 Javascript
JavaScript中的对象序列化介绍
2014/12/30 Javascript
jQuery获取Table某列的值(推荐)
2017/03/03 Javascript
nodejs集成sqlite使用示例
2017/06/05 NodeJs
jQuery实现的弹幕效果完整实例
2017/09/06 jQuery
Windows下Node爬虫神器Puppeteer安装记
2019/01/09 Javascript
微信小程序3种位置API的使用方法详解
2019/08/05 Javascript
微信小程序如何通过用户授权获取手机号(getPhoneNumber)
2020/01/21 Javascript
从零开始用webpack构建一个vue3.0项目工程的实现
2020/09/24 Javascript
Python新手在作用域方面经常容易碰到的问题
2015/04/03 Python
python导出chrome书签到markdown文件的实例代码
2017/12/27 Python
Python获取系统所有进程PID及进程名称的方法示例
2018/05/24 Python
python多进程控制学习小结
2018/10/31 Python
Python 等分切分数据及规则命名的实例代码
2019/08/16 Python
Python中url标签使用知识点总结
2020/01/16 Python
python实现用类读取文件数据并计算矩形面积
2020/01/18 Python
将自己的数据集制作成TFRecord格式教程
2020/02/17 Python
python中有帮助函数吗
2020/06/19 Python
详解python中的异常和文件读写
2021/01/03 Python
tensorflow与numpy的版本兼容性问题的解决
2021/01/08 Python
利用css3实现的简单的鼠标悬停按钮
2014/11/04 HTML / CSS
CSS3 :default伪类选择器使用简介
2018/03/15 HTML / CSS
香港钟表珠宝首饰商城:OneMallTime网摩间
2016/10/14 全球购物
美国花布包包品牌:Vera Bradley
2017/08/11 全球购物
Made in Design英国:设计家具、照明、家庭装饰和花园家具
2019/09/24 全球购物
中专生学习生活的自我评价分享
2013/10/27 职场文书
单位消防安全制度
2014/01/12 职场文书
党员承诺书内容
2014/03/26 职场文书
八荣八耻的活动方案
2014/08/16 职场文书
租车协议书
2015/01/27 职场文书
国际贸易实训总结
2015/08/03 职场文书