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 相关文章推荐
Zend公司全球首推PHP认证
Oct 09 PHP
用session做客户验证时的注意事项
Oct 09 PHP
探讨php中遍历二维数组的几种方法详解
Jun 08 PHP
php中文验证码实现示例分享
Jan 12 PHP
小谈php正则提取图片地址
Mar 27 PHP
php+xml实现在线英文词典之添加词条的方法
Jan 23 PHP
WordPress中登陆后关闭登陆页面及设置用户不可见栏目
Dec 31 PHP
详解WordPress中的头像缓存和代理中的缓存更新方法
Mar 01 PHP
php简单的上传类分享
May 15 PHP
php入门教程之Zend Studio设置与开发实例
Sep 09 PHP
PHP中单例模式与工厂模式详解
Feb 17 PHP
PHP自定义递归函数实现数组转JSON功能【支持GBK编码】
Jul 17 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 cc攻击代码与防范方法
2012/10/18 PHP
浅谈php中include文件变量作用域
2015/06/18 PHP
PHP+Jquery与ajax相结合实现下拉淡出瀑布流效果【无需插件】
2016/05/06 PHP
js 数组实现一个类似ruby的迭代器
2009/10/27 Javascript
js post方式传递提交的实现代码
2010/05/31 Javascript
TinyMCE 新增本地图片上传功能
2010/11/05 Javascript
使用基于jquery的gamequery插件做JS乒乓球游戏
2011/07/31 Javascript
JavaScript函数定义的常见注意事项小结
2014/09/16 Javascript
Javascript常用小技巧汇总
2015/06/24 Javascript
js控制TR的显示隐藏
2016/03/04 Javascript
jQuery validate插件功能与用法详解
2016/12/15 Javascript
Node.js查找当前目录下文件夹实例代码
2017/03/07 Javascript
移动端网页开发调试神器Eruda的介绍与使用技巧
2017/10/30 Javascript
angularJs 表格添加删除修改查询方法
2018/02/27 Javascript
JS基于Location实现访问Url、重定向及刷新页面的方法分析
2018/12/03 Javascript
深入理解Vue.js轻量高效的前端组件化方案
2018/12/10 Javascript
基于Vue+ElementUI的省市区地址选择通用组件
2019/11/20 Javascript
基于node+vue实现简单的WebSocket聊天功能
2020/02/01 Javascript
如何使用three.js 制作一个三维的推箱子游戏
2020/07/29 Javascript
[01:09]DOTA2次级职业联赛 - 99战队宣传片
2014/12/01 DOTA
python 动态获取当前运行的类名和函数名的方法
2014/04/15 Python
使用python在本地电脑上快速处理数据
2017/06/22 Python
Python去除、替换字符串空格的处理方法
2018/04/01 Python
python批量导入数据进Elasticsearch的实例
2018/05/30 Python
python 获得任意路径下的文件及其根目录的方法
2019/02/16 Python
解决Python3 控制台输出InsecureRequestWarning问题
2019/07/15 Python
PyCharm下载和安装详细步骤
2019/12/17 Python
一文读懂python Scrapy爬虫框架
2021/02/24 Python
美国购买隐形眼镜网站:Lenses For Less
2020/07/05 全球购物
static全局变量与普通的全局变量有什么区别?static局部变量和普通局部变量有什么区别?static函数与普通函数有什么区别?
2015/02/22 面试题
社区禁毒工作方案
2014/06/02 职场文书
特此通知格式
2015/04/27 职场文书
家庭暴力离婚起诉书
2015/05/18 职场文书
大学生学生会工作总结2015
2015/05/26 职场文书
Python 处理表格进行成绩排序的操作代码
2021/07/26 Python
Python 中的Sympy详细使用
2021/08/07 Python