PHP如何创建简单RPC服务

发布时间:2021-09-07 10:29:32 作者:小新
来源:亿速云 阅读:134

小编给大家分享一下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如何创建简单RPC服务

服务端 

<?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

PHP如何创建简单RPC服务

Server

PHP如何创建简单RPC服务

以上是“PHP如何创建简单RPC服务”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注亿速云行业资讯频道!

推荐阅读:
  1. 怎么启动http服务和rpc服务
  2. 简单RPC框架-基于Consul的服务注册与发现

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

php rpc

上一篇:PHP如何实现WebSocket

下一篇:MySQL性能调优技巧以及Monyog线程缓存监测

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》