PHP创建简单RPC服务案例详解

RPC 定义

RPC(Remote Procedure Call)即远程过程调用,指被调用方法的具体实现不在程序运行本地,而是在别的某个地方。主要应用于不同的系统之间的远程通信和相互调用。

如 A 调用 B 提供的 remoteAdd 方法:

  1. 首先A与B之间建立一个TCP连接;
  2. 然后A把需要调用的方法名(这里是remoteAdd)以及方法参数(10, 20)序列化成字节流发送出去;
  3. B接受A发送过来的字节流,然后反序列化得到目标方法名,方法参数,接着执行相应的方法调用(可能是localAdd)并把结果30返回;
  4. A接受远程调用结果

有些远程调用选择比较底层的 socket 协议,有些远程调用选择比较上层的 HTTP 协议。

远程调用的好处:

  • 解耦:当方法提供者需要对方法内实现修改时,调用者完全感知不到,不用做任何变更;这种方式在跨部门,跨公司合作的时候经常用到,并且方法的提供者我们通常称为:服务的暴露方

这里使用 PHP Socket 来创建一个服务端和客户端,目录结构如下:

服务端 

<?php
class RpcServer {
    protected $server = null;

    public function __construct($host, $port, $path)
    {
        // 创建一个 Socket 服务
        if(($this->server = socket_create(AF_INET,SOCK_STREAM,SOL_TCP)) < 0) {
            exit("socket_create() 失败的原因是:".socket_strerror($this->server)."\n");
        }
        if(($ret = socket_bind($this->server,$host,$port)) < 0) {
            exit("socket_bind() 失败的原因是:".socket_strerror($ret)."\n");
        }
        if(($ret = socket_listen($this->server,3)) < 0) {
            exit("socket_listen() 失败的原因是:".socket_strerror($ret)."\n");
        }

        // 判断 RPC 服务目录是否存在
        $realPath = realpath(__DIR__ . $path);
        if ($realPath === false || !file_exists($realPath)) {
            exit("{$path} error \n");
        }

        do {
            $client = socket_accept($this->server);
            if($client) {
                // 一次性读取
                $buf = socket_read($client, 8024);
                echo $buf;

                //解析客户端发送过来的协议
                $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]);
                    $method = $method[1];
                    $params = json_decode($params[1], true);
                    $file = $realPath . '/' . $class . '.php';  // 类文件需要和类名一致
                    $data = ''; // 执行结果
                    // 判断类文件是否存在
                    if(file_exists($file)) {
                        // 引入类文件
                        require_once $file;
                        // 实例化类
                        $rfc_obj = new ReflectionClass($class);
                        // 判断该类指定方法是否存在
                        if($rfc_obj->hasMethod($method)) {
                            // 执行类方法
                            $rfc_method = $rfc_obj->getMethod($method);
                            $data = $rfc_method->invokeArgs($rfc_obj->newInstance(), [$params]);
                        } else {
                            socket_write($client, 'method error');
                        }
                        //把运行后的结果返回给客户端
                        socket_write($client, $data);
                    }
                } else {
                    socket_write($client, 'class or method error');
                }

                // 关闭客户端
                socket_close($client);
            }

        }while(true);
    }

    public function __destruct()
    {
        socket_close($this->server);
    }
}

new RpcServer('127.0.0.1',8080,'./service');

客户端

<?php
class RpcClient {
    protected $client = null;
    protected $url_info = [];   // 远程调用 URL 组成部分

    public function __construct($url)
    {
        // 解析 URL
        $this->url_info = parse_url($url);
    }

    public function __call($name, $arguments)
    {
        // 创建一个客户端
        $this->client = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
        if(!$this->client) {
            exit('socket_create() 失败');
        }
        socket_connect($this->client, $this->url_info['host'], $this->url_info['port']);

        // 传递调用的类名
        $class = basename($this->url_info['path']);
        // 传递调用的参数
        $args = '';
        if(isset($arguments[0])) {
            $args = json_encode($arguments[0]);
        }
        // 向服务端发送我们自定义的协议数据
        $proto = "Rpc-Class: {$class};".PHP_EOL
            ."Rpc-Method: {$name};".PHP_EOL
            ."Rpc-Params: {$args};".PHP_EOL;
        socket_write($this->client, $proto);
        // 读取服务端传来的数据
        $buf = socket_read($this->client, 8024);
        socket_close($this->client);
        return $buf;
    }
}

$rpcClient = new RpcClient('http://127.0.0.1:8080/news');
echo $rpcClient->display(['title'=>'txl']);
echo $rpcClient->display(['title'=>'hello world']);

服务类 News

<?php
class News {
    public function display($data)
    {
        return json_encode(['result'=>"News display(), title is {$data['title']}"]);
    }
}

运行测试:

Client

Server

到此这篇关于PHP创建简单RPC服务案例详解的文章就介绍到这了,更多相关PHP创建简单RPC服务内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • php实现的一个简单json rpc框架实例

    json rpc 是一种以json为消息格式的远程调用服务,它是一套允许运行在不同操作系统.不同环境的程序实现基于Internet过程调用的规范和一系列的实现.这种远程过程调用可以使用http作为传输协议,也可以使用其它传输协议,传输的内容是json消息体. 下面我们code一套基于php的rpc框架,此框架中包含rpc的服务端server,和应用端client: (一)PHP服务端RPCserver jsonRPCServer.php 复制代码 代码如下: class jsonRPCServe

  • php xml-rpc远程调用

    复制代码 代码如下: <?php /* 从网上找来的XML-RPC库,对于开发小型的外部通讯接口很有用 */ function & XML_serialize($data, $level = 0, $prior_key = NULL){ #assumes a hash, keys are the variable names $xml_serialized_string = ""; while(list($key, $value) = each($data)){ $inl

  • 详解php中流行的rpc框架

    什么是RPC框架? 通常我们调用一个php中的方法,比如这样一个函数方法: localAdd(10, 20),localAdd方法的具体实现要么是用户自己定义的,要么是php库函数中自带的,也就说在localAdd方法的代码实现在本地,它是一个本地调用! 远程调用原理 比如 A (client) 调用 B (server) 提供的remoteAdd方法: 1.首先A与B之间建立一个TCP连接: 2.然后A把需要调用的方法名(这里是remoteAdd)以及方法参数(10, 20)序列化成字节流发送

  • AMFPHP php远程调用(RPC, Remote Procedure Call)工具 快速入门教程

    它可以使PHP与下述技术无缝通信: (1) Flash 和 Flex Remoting (2) JavaScript JSON 和 Ajax JSON (3) XML 和XML-RPC 什么是RPC 远端程序调用(RPC, Remote Procedure Call) 是一种客户端与服务器端交换数据方式.我们可以调用本地对象带对各种参数方法设置回调并接受调用结果.我们不用关心发送和接收数据的实现细节.实现细节通常是抽象的,就像我们在调用本地方法一样. AMFPHP的工作原理 客户端(Flash

  • PHP采用XML-RPC构造Web Service实例教程

    一.概述: 目前进行Web Service通信有两种协议标准,一种是XML-RPC,另外一种是SOAP.XML-RPC比较简单,出现时间比较早,SOAP比较复杂,主要是一些需要稳定.健壮.安全并且复杂交互的时候使用. PHP自身就集成了XML-RPC和SOAP两种协议的访问,都是集中在xmlrpc扩展当中.另外,在PHP的PEAR中,不管是PHP 4还是PHP 5,都已经默认集成了XML-RPC扩展,而且该扩展跟xmlrpc扩展无关,能够独立实现XML-RPC的协议交互,如果没有xmlrpc扩展

  • PHP创建简单RPC服务案例详解

    RPC 定义 RPC(Remote Procedure Call)即远程过程调用,指被调用方法的具体实现不在程序运行本地,而是在别的某个地方.主要应用于不同的系统之间的远程通信和相互调用. 如 A 调用 B 提供的 remoteAdd 方法: 首先A与B之间建立一个TCP连接: 然后A把需要调用的方法名(这里是remoteAdd)以及方法参数(10, 20)序列化成字节流发送出去: B接受A发送过来的字节流,然后反序列化得到目标方法名,方法参数,接着执行相应的方法调用(可能是localAdd)并

  • Android Location服务之LocationManager案例详解

    上次介绍了位置服务中的Geocoder,这次就来介绍一下LocationManager.LocationManager系统服务是位置服务的核心组件,它提供了一系列方法来处理与位置相关的问题,包括查询上一个已知位置.注册和注销来自某个LocationProvider的周期性的位置更新.注册和注销接近某个坐标时对一个已定义的Intent的触发等.今天我们就一起探讨一下LocationManager的简单应用. 在进入正题之前,朋友们需要了解与LocationManager相关的两个知识点: prov

  • Java SPI简单应用案例详解

    开篇 本文主要谈一下 Java SPI(Service Provider Interface) ,因为最近在看 Dubbo 的相关内容,其中涉及到了 一个概念- Dubbo SPI, 最后又牵扯出来了 JAVA SPI, 所以先从 Java SPI 开整. 正文 平常学习一个知识点,我们的常规做法是: 是什么 有什么用 怎么用 这次我们倒着做,先不谈什么是 SPI 及其作用,来看下如何使用. 使用 1. 创建一个 maven 工程 2. 创建一个接口类以及实现类 // 接口 public int

  • Android AlertDialog六种创建方式案例详解

    目录 一.setMessage:设置对话框内容为简单文本内容 二.setItem:设置文本框内容为简单列表项 三.setSingleChoiceItems()设置对话框内容为单选列表项 四.setMultiChoiceItems()设置对话框内容为多选项列表 五.setAdapter()设置对话框内容为自定义列表项(这里是一个布局) 六.setView()设置对话框为自定义View 创建AlertDialog的步骤: 创建AlertDialog.Builder对象 调用Builder对象的set

  • Android AlertDialog多种创建方式案例详解

    目录 一.setMessage:设置对话框内容为简单文本内容 二.setItem:设置文本框内容为简单列表项 三.setSingleChoiceItems()设置对话框内容为单选列表项 四.setMultiChoiceItems()设置对话框内容为多选项列表 五.setAdapter()设置对话框内容为自定义列表项(这里是一个布局) 六.setView()设置对话框为自定义View 创建AlertDialog的步骤: 创建AlertDialog.Builder对象 调用Builder对象的set

  • Java Hibernate使用SessionFactory创建Session案例详解

        SessionFactory在Hibernate中实际上起到了一个缓冲区的作用 他缓冲了HIbernate自动生成SQL语句和其他的映射数据 还缓冲了一些将来有可能重复利用的数据     为了能创建一个SessionFactory对象 应该在Hibernate初始化的时候创建一个Configuration类的实例 并将已经写好的映射文件交给他处理 这样Configuration对象就可以创建一个SessionFactory对象 当SessionFactory对象创建成功后 Configu

  • Java 使用maven实现Jsoup简单爬虫案例详解

    一.Jsoup的简介         jsoup 是一款Java 的HTML解析器,可直接解析某个URL地址.HTML文本内容.它提供了一套非常省力的API,可通过DOM,CSS以及类似于jQuery的操作方法来取出和操作数据 二.我们可以利用Jsoup做什么         2.1从URL,文件或字符串中刮取并解析HTML查找和提取数据,         2.2使用DOM遍历或CSS选择器操纵HTML元素,属性和文本         2.3从而使我们输出我们想要的整洁文本 三.利用Jsoup爬

  • Python中的tkinter库简单案例详解

    目录 案例一 Label & Button 标签和按钮 案例二 Entry & Text 输入和文本框 案例三 Listbox 部件 案例四 Radiobutton 选择按钮 案例五 Scale 尺度 案例六 Checkbutton 勾选项 案例七 Canvas 画布 案例八 Menubar 菜单 案例九 Frame 框架 案例十 messagebox 弹窗 案例十一 pack grid place 放置 登录窗口 TKinterPython 的 GUI 库非常多,之所以选择 Tkinte

  • Android AS创建自定义布局案例详解

    先创建一个title.xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" andr

  • Java Spring Boot消息服务万字详解分析

    目录 消息服务概述 为什么要使用消息服务 异步处理 应用解耦 流量削峰 分布式事务管理 常用消息中间件介绍 ActiveMQ RabbitMQ RocketMQ RabbitMQ消息中间件 RabbitMQ简介 RabbitMQ工作模式介绍 Work queues(工作队列模式) Public/Subscribe(发布订阅模式) Routing(路由模式) Topics(通配符模式) RPC Headers RabbitMQ安装以及整合环境搭建 安装RabbitMQ 下载RabbitMQ 安装R

随机推荐