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 和 MySQL 基础教程(三)
Oct 09 PHP
PHP写MySQL数据 实现代码
Jun 15 PHP
php中var_export与var_dump的区别分析
Aug 21 PHP
PHP游戏编程25个脚本代码
Feb 08 PHP
应用开发中涉及到的css和php笔记分享
Aug 02 PHP
php笔记之:初探PHPcms模块开发介绍
Apr 26 PHP
php中过滤非法字符的具体实现
Oct 29 PHP
ThinkPHP单字母函数(快捷方法)使用总结
Jul 23 PHP
php实现smarty模板无限极分类的方法
Dec 07 PHP
PHP模板引擎Smarty之配置文件在模板变量中的使用方法示例
Apr 11 PHP
PHP树形结构tree类用法示例
Feb 01 PHP
浅谈Laravel中的三种中间件的作用
Oct 13 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
解析posix与perl标准的正则表达式区别
2013/06/17 PHP
php+mysql实现无限分类实例详解
2015/01/15 PHP
jquery 简单图片导航插件jquery.imgNav.js
2010/03/17 Javascript
JQuery中基础过滤选择器用法实例分析
2015/05/18 Javascript
javascript单例模式的简单实现方法
2015/07/25 Javascript
jQuery检测滚动条是否到达底部
2015/12/15 Javascript
JS 清除字符串数组中,重复元素的实现方法
2016/05/24 Javascript
用js实现博客打赏功能
2016/10/24 Javascript
微信小程序 icon组件详细及实例代码
2016/10/25 Javascript
关于jquery form表单序列化的注意事项详解
2017/08/01 jQuery
Vue2几种常见开局方式详解
2017/09/09 Javascript
使用 Node.js 开发资讯爬虫流程
2018/01/07 Javascript
JS实现的抛物线运动效果示例
2018/01/30 Javascript
JavaScript实现的DOM绘制柱状图效果示例
2018/08/08 Javascript
js实现删除li标签一行内容
2019/04/16 Javascript
layui table 表格上添加日期控件的两种方法
2019/09/28 Javascript
[01:02:53]DOTA2上海特级锦标赛主赛事日 - 5 总决赛Liquid VS Secret第二局
2016/03/06 DOTA
python实现文件分组复制到不同目录的例子
2014/06/04 Python
跟老齐学Python之玩转字符串(1)
2014/09/14 Python
Pipenv一键搭建python虚拟环境的方法
2018/05/22 Python
pycham查看程序执行的时间方法
2018/11/29 Python
python-django中的APPEND_SLASH实现方法
2019/06/21 Python
Python模块的制作方法实例分析
2019/12/21 Python
Python Request类源码实现方法及原理解析
2020/08/17 Python
20行Python代码实现一款永久免费PDF编辑工具的实现
2020/08/27 Python
python ssh 执行shell命令的示例
2020/09/29 Python
python语言time库和datetime库基本使用详解
2020/12/25 Python
CSS3制作半透明边框(Facebox)类似渐变
2012/12/09 HTML / CSS
图片上传插件ImgUploadJS:用HTML5 File API 实现截图粘贴上传、拖拽上传
2016/01/20 HTML / CSS
Qoo10台湾站:亚洲领先的在线市场
2018/05/15 全球购物
用缩写的指针比较"if(p)" 检查空指针是否可靠?如果空指针的内部表达不是0会怎么样?
2014/01/05 面试题
市场营销个人求职信范文
2014/02/02 职场文书
党员查摆问题及整改措施
2014/10/10 职场文书
2015年助残日活动总结
2015/03/27 职场文书
2015年司法所工作总结
2015/04/27 职场文书
搞笑婚庆主持词
2015/06/29 职场文书