首页后端开发PHPPHP怎样实现创建简单的RPC?方法是什么?

PHP怎样实现创建简单的RPC?方法是什么?

时间2024-03-26 08:34:03发布访客分类PHP浏览557
导读:这篇文章给大家分享的是PHP怎样实现创建简单的RPC的内容。下文对RPC服务以及如果创建PRC服务都有详细的介绍,有这方面学习需要的朋友可以参考看看,那么感兴趣的朋友接下来一起跟随小编学习一下吧。RPC 定义 RPC(Remote Proc...

这篇文章给大家分享的是PHP怎样实现创建简单的RPC的内容。下文对RPC服务以及如果创建PRC服务都有详细的介绍,有这方面学习需要的朋友可以参考看看,那么感兴趣的朋友接下来一起跟随小编学习一下吧。

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的问题有帮助,想要了解更多可以关注其它的相关文章。

文本转载自脚本之家

声明:本文内容由网友自发贡献,本站不承担相应法律责任。对本内容有异议或投诉,请联系2913721942#qq.com核实处理,我们将尽快回复您,谢谢合作!


若转载请注明出处: PHP怎样实现创建简单的RPC?方法是什么?
本文地址: https://pptw.com/jishu/653382.html
PHP里fopen生成文件出现中文乱码怎么办? Goshi是如何通过结构struct实现接口interface的呢?

游客 回复需填写必要信息