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伪静态页面函数附使用方法
Jun 20 PHP
php横向重复区域显示二法
Sep 25 PHP
PHP 错误之引号中使用变量
May 04 PHP
Godaddy空间Zend Optimizer升级方法
May 10 PHP
php页面防重复提交方法总结
Nov 25 PHP
Linux下编译redis和phpredis的方法
Apr 07 PHP
PHP不使用内置函数实现字符串转整型的方法示例
Jul 03 PHP
PHP调用API接口实现天气查询功能的示例
Sep 21 PHP
PHP空值检测函数与方法汇总
Nov 19 PHP
Laravel5.5以下版本中如何自定义日志行为详解
Aug 01 PHP
php+ajax实现商品对比功能示例
Apr 13 PHP
详解Laravel服务容器的优势
May 29 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查询数据库中满足条件的记录条数(两种实现方法)
2013/01/29 PHP
探讨PHP函数ip2long转换IP时数值太大产生负数的解决方法
2013/06/06 PHP
PHP_SELF,SCRIPT_NAME,REQUEST_URI区别
2014/12/24 PHP
PHP+shell实现多线程的方法
2015/07/01 PHP
php好代码风格的阶段性总结
2016/06/25 PHP
PHP date_default_timezone_set()设置时区操作实例分析
2020/05/16 PHP
JS提交并解析后台返回的XML的代码
2008/11/03 Javascript
javascript面向对象编程(一) 实例代码
2010/06/25 Javascript
那些年,我还在学习jquery 学习笔记
2012/03/05 Javascript
Jquery实现简单的动画效果代码
2012/03/18 Javascript
jQuery 全选/反选以及单击行改变背景色实例
2013/07/02 Javascript
JS案例分享之金额小写转大写
2014/05/15 Javascript
javascript 判断两个日期之差的示例代码
2015/09/05 Javascript
你所未知的3种Node.js代码优化方式
2016/02/25 Javascript
Angularjs 创建可复用组件实例代码
2016/10/09 Javascript
vue开发心得和技巧分享
2016/10/27 Javascript
jQuery实现的浮动层div浏览器居中显示效果
2017/02/03 Javascript
React Js 微信禁止复制链接分享禁止隐藏右上角菜单功能
2017/05/26 Javascript
JavaScript简介_动力节点Java学院整理
2017/06/26 Javascript
使用Bootstrap + Vue.js实现表格的动态展示、新增和删除功能
2017/11/27 Javascript
加快Vue项目的开发速度的方法
2018/12/12 Javascript
vue滚动固定顶部及修改样式的实例代码
2019/05/30 Javascript
javascript实现异形滚动轮播
2019/11/28 Javascript
[01:00:59]VP VS VG Supermajor小组赛胜者组第二轮 BO3第二场 6.2
2018/06/03 DOTA
Python操作json数据的一个简单例子
2014/04/17 Python
python编写微信远程控制电脑的程序
2018/01/05 Python
python实现聊天小程序
2018/03/13 Python
详解flask入门模板引擎
2018/07/18 Python
python+selenium实现自动化百度搜索关键词
2019/06/03 Python
python设置随机种子实例讲解
2019/09/12 Python
解决python3输入的坑——input()
2020/12/05 Python
美国婴童服装市场上的领先品牌:Carter’s
2018/02/08 全球购物
Sneaker Studio乌克兰:购买运动鞋
2018/03/26 全球购物
加拿大在线隐形眼镜和眼镜店:VisionPros
2019/10/06 全球购物
工人先锋号事迹材料
2014/12/24 职场文书
python基于OpenCV模板匹配识别图片中的数字
2021/03/31 Python