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 相关文章推荐
web方式ftp
Oct 09 PHP
多重?l件?合查?(一)
Oct 09 PHP
使用php判断网页是否gzip压缩
Jun 25 PHP
PHP实现的简单三角形、矩形周长面积计算器分享
Nov 18 PHP
Laravel中使用阿里云OSS Composer包分享
Feb 10 PHP
Zend Framework入门之环境配置及第一个Hello World示例(附demo源码下载)
Mar 21 PHP
linux下php上传文件注意事项
Jun 11 PHP
ThinkPHP 模板引擎使用详解
May 07 PHP
详解PHP如何更好的利用PHPstorm的自动提示
Aug 18 PHP
OAuth认证协议中的HMACSHA1加密算法(实例)
Oct 25 PHP
laravel 解决多库下的DB::transaction()事务失效问题
Oct 21 PHP
YII2框架中日志的配置与使用方法实例分析
Mar 18 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
自动分页的不完整解决方案
2007/01/12 PHP
smarty简单应用实例
2015/11/03 PHP
Laravel重写用户登录简单示例
2016/10/08 PHP
php实现图片按比例截取的方法
2017/02/06 PHP
PHP+redis实现的限制抢购防止商品超发功能详解
2019/09/19 PHP
解决在laravel中auth建立时候遇到的问题
2019/10/15 PHP
PhpStorm连接服务器并实现自动上传功能
2020/12/09 PHP
Jquery时间验证和转换工具小例子
2013/07/01 Javascript
小议JavaScript中Generator和Iterator的使用
2015/07/29 Javascript
jQuery实现的fixedMenu下拉菜单效果代码
2015/08/24 Javascript
jQuery+ajax+asp.net获取Json值的方法
2016/06/08 Javascript
JavaScript在form表单中使用button按钮实现submit提交方法
2017/01/23 Javascript
微信小程序开发之从相册获取图片 使用相机拍照 本地图片上传
2017/04/18 Javascript
vue服务端渲染的实例代码
2017/08/28 Javascript
纯js实现画一棵树的示例
2017/09/05 Javascript
node.js使用redis储存session的方法
2018/09/26 Javascript
详解基于Wepy开发小程序插件(推荐)
2019/08/01 Javascript
vue element upload实现图片本地预览
2019/08/20 Javascript
新手入门js闭包学习过程解析
2019/10/08 Javascript
vue+elementui通用弹窗的实现(新增+编辑)
2021/01/07 Vue.js
[52:52]完美世界DOTA2联赛PWL S3 LBZS vs access 第一场 12.10
2020/12/13 DOTA
python实现简单聊天应用 python群聊和点对点均实现
2017/09/14 Python
解析PyCharm Python运行权限问题
2020/01/08 Python
开启Django博客的RSS功能的实现方法
2020/02/17 Python
python多项式拟合之np.polyfit 和 np.polyld详解
2020/02/18 Python
详解用python -m http.server搭一个简易的本地局域网
2020/09/24 Python
银行会计业务的个人自我评价
2013/11/02 职场文书
门卫岗位职责
2013/11/15 职场文书
秘书英文求职信范文
2014/01/31 职场文书
《巨人的花园》教学反思
2014/02/12 职场文书
十佳党员事迹材料
2014/08/28 职场文书
自主招生推荐信格式模板
2015/03/24 职场文书
2015秋季开学演讲稿范文
2015/07/16 职场文书
小学英语教学随笔
2015/08/14 职场文书
Python办公自动化之教你如何用Python将任意文件转为PDF格式
2021/06/28 Python
html5表单的required属性使用
2021/07/07 HTML / CSS