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数组函数
Aug 18 PHP
Window 7/XP 安装Apache 2.4与PHP 5.4 的过程详解
Jun 02 PHP
非常实用的php弹出错误警告函数扩展性强
Jan 17 PHP
php实现MySQL数据库备份与还原类实例
Dec 09 PHP
Codeigniter通过SimpleXML将xml转换成对象的方法
Mar 19 PHP
smarty模板引擎之内建函数用法
Mar 30 PHP
PHP整合七牛实现上传文件
Jul 03 PHP
ECSHOP在PHP5.5及高版本上报错的解决方法
Aug 31 PHP
PHP执行linux命令常用函数汇总
Feb 02 PHP
php+flash+jQuery多图片上传源码分享
Jul 27 PHP
深入解析Laravel5.5中的包自动发现Package Auto Discovery
Sep 13 PHP
thinkphp5.1 框架钩子和行为用法实例分析
May 25 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/10/09 PHP
PHP版本升级到7.x后wordpress的一些修改及wordpress技巧
2015/12/25 PHP
有关于eclipse配置spket需要注意的一些地方
2013/04/07 Javascript
js导出txt示例代码
2014/01/14 Javascript
js打开windows上的可执行文件示例
2014/05/27 Javascript
全面解析Bootstrap中nav、collapse的使用方法
2016/05/22 Javascript
javascript 组合按键事件监听实现代码
2017/02/21 Javascript
使用vue制作FullPage页面滚动效果
2017/08/21 Javascript
jquery tmpl模板(实例讲解)
2017/09/02 jQuery
bootstrap Table服务端处理分页(后台是.net)
2017/10/19 Javascript
浅谈jquery fullpage 插件增加头部和版权的方法
2018/03/20 jQuery
对layui中table组件工具栏的使用详解
2019/09/19 Javascript
node.js 微信开发之定时获取access_token
2020/02/07 Javascript
JavaScript实现简单验证码
2020/08/24 Javascript
在antd中setFieldsValue和defaultVal的用法
2020/10/29 Javascript
JS hasOwnProperty()方法检测一个属性是否是对象的自有属性的方法
2021/01/29 Javascript
[03:03]2014DOTA2西雅图国际邀请赛 Alliance战队巡礼
2014/07/07 DOTA
Python中的fileinput模块的简单实用示例
2015/07/09 Python
python3.5使用tkinter制作记事本
2016/06/20 Python
一张图带我们入门Python基础教程
2017/02/05 Python
Python线性方程组求解运算示例
2018/01/17 Python
Python生成器generator用法示例
2018/08/10 Python
浅谈python下tiff图像的读取和保存方法
2018/12/04 Python
Python使用__new__()方法为对象分配内存及返回对象的引用示例
2019/09/20 Python
使用python将最新的测试报告以附件的形式发到指定邮箱
2019/09/20 Python
在Python中使用turtle绘制多个同心圆示例
2019/11/23 Python
python统计字符的个数代码实例
2020/02/07 Python
Python自动采集微信联系人的实现示例
2020/02/28 Python
Python实现检测文件的MD5值来查找重复文件案例
2020/03/12 Python
python实现飞船大战
2020/04/24 Python
python3.6使用SMTP协议发送邮件
2020/05/20 Python
使用Keras 实现查看model weights .h5 文件的内容
2020/06/09 Python
大学校务公开实施方案
2014/03/31 职场文书
住宅使用说明书
2014/05/09 职场文书
学校安全责任书范本
2014/07/23 职场文书
党员批评与自我批评范文
2014/09/23 职场文书