我的编程空间,编程开发者的网络收藏夹
学习永远不晚

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

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

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服务内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

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

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

创建简单的node服务器实例(分享)

话不多说直接上代码:var http = require('http')//对URL 解析为对象 //1.导入模块 URl模块var url = require('url') var fs = require('fs') var path
2022-06-04

Nodejs 搭建简单的Web服务器详解及实例

使用 Nodejs 搭建简单的Web服务器 使用Nodejs搭建Web服务器是学习Node.js比较全面的入门教程,因为要完成一个简单的Web服务器,你需要学习Nodejs中几个比较重要的模块,比如:http协议模块、文件系统、url解析模
2022-06-04

搭建简单的nodejs http服务器详解

搭建简单的nodejs服务器 通过一些简单配置我们就可以搭建一台基于nodejs的http服务器 通过switch配置url路由的方法// 这是一个简单的Node HTTP服务器,能处理当前目录的文件 // 并能实现两种特殊的URL用于测试
2022-06-04

轻松创建nodejs服务器(1):一个简单nodejs服务器例子

我们先来实现一个简单的例子,hello world。 似乎每种语言教程的第一节都会讲这个,我们也不例外。 首先我们先创建一个项目目录,目录可自己定义,本案例的目录为 e:/nodetest/。 由于我们要搭建的是服务器,所以我把第一个文件命
2022-06-04

Golang实现简单http服务器的示例详解

这篇文章主要为大家详细介绍了如何利用Golang实现简单http服务器,文中的示例代码讲解详细,对我们学习Golang有一定的帮助,需要的可以参考一下
2023-03-20

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录