zoukankan      html  css  js  c++  java
  • rpc基本思路

    参考:

    https://www.jianshu.com/p/dd9dd3476772 (php实现简单的rpc)

    rpc简介

    RPC全称为Remote Procedure Call,翻译过来为“远程过程调用”。目前,主流的平台中都支持各种远程调用技术,以满足分布式系统架构中不同的系统之间的远程通信和相互调用。远程调用的应用场景极其广泛,实现的方式也各式各样。

    rpc可以跨平台和开发语言

     

    rpc使用的通信协议

    基于HTTP协议的(例如基于文本的SOAP(XML)、Rest(JSON),基于二进制Hessian(Binary))
    基于TCP协议的(通常会借助Mina、Netty等高性能网络框架)
     

    rpc的调用过程

    同步通信调用(同步RPC)
    异步通信调用(MQ、异步RPC)
     

     

    rpc服务端 

    <?php
    /**
     * User: yuzhao
     * CreateTime: 2018/11/15 下午11:46
     * Description: Rpc服务端
     */
    class RpcServer {
    
        /**
         * User: yuzhao
         * CreateTime: 2018/11/15 下午11:51
         * @var array
         * Description: 此类的基本配置
         */
        private $params = [
            'host'  => '',  // ip地址,列出来的目的是为了友好看出来此变量中存储的信息
            'port'  => '', // 端口
            'path'  => '' // 服务目录
        ];
    
        /**
         * User: yuzhao
         * CreateTime: 2018/11/16 上午12:14
         * @var array
         * Description: 本类常用配置
         */
        private $config = [
            'real_path' => '',
            'max_size'  => 2048 // 最大接收数据大小
        ];
    
        /**
         * User: yuzhao
         * CreateTime: 2018/11/15 下午11:50
         * @var nul
         * Description:
         */
        private $server = null;
    
        /**
         * Rpc constructor.
         */
        public function __construct($params)
        {
            $this->check();
            $this->init($params);
        }
    
        /**
         * User: yuzhao
         * CreateTime: 2018/11/16 上午12:0
         * Description: 必要验证
         */
        private function check() {
            $this->serverPath();
        }
    
        /**
         * User: yuzhao
         * CreateTime: 2018/11/15 下午11:48
         * Description: 初始化必要参数
         */
        private function init($params) {
            // 将传递过来的参数初始化
            $this->params = $params;
            // 创建tcpsocket服务
            $this->createServer();
        }
    
        /**
         * User: yuzhao
         * CreateTime: 2018/11/16 上午12:0
         * Description: 创建tcpsocket服务
    
         */
        private function createServer() {
            $this->server = stream_socket_server("tcp://{$this->params['host']}:{$this->params['port']}", $errno,$errstr);
            if (!$this->server) exit([
                $errno,$errstr
            ]);
        }
    
        /**
         * User: yuzhao
         * CreateTime: 2018/11/15 下午11:57
         * Description: rpc服务目录
         */
        public function serverPath() {
            $path = $this->params['path'];
            $realPath = realpath(__DIR__ . $path);
            if ($realPath === false ||!file_exists($realPath)) {
                exit("{$path} error!");
            }
            $this->config['real_path'] = $realPath;
        }
    
        /**
         * User: yuzhao
         * CreateTime: 2018/11/15 下午11:51
         * Description: 返回当前对象
         */
        public static function instance($params) {
            return new RpcServer($params);
        }
    
        /**
         * User: yuzhao
         * CreateTime: 2018/11/16 上午12:06
         * Description: 运行
         */
        public function run() {
            while (true) {
                $client = stream_socket_accept($this->server);
                if ($client) {
                    echo "有新连接
    ";
                    $buf = fread($client, $this->config['max_size']);
                    print_r('接收到的原始数据:'.$buf."
    ");
                    // 自定义协议目的是拿到类方法和参数(可改成自己定义的)
                    $this->parseProtocol($buf,$class, $method,$params);
                    // 执行方法
                    $this->execMethod($client, $class, $method, $params);
                    //关闭客户端
                    fclose($client);
                    echo "关闭了连接
    ";
                }
            }
        }
    
        /**
         * User: yuzhao
         * CreateTime: 2018/11/16 上午12:19
         * @param $class
         * @param $method
         * @param $params
         * Description: 执行方法
         */
        private function execMethod($client, $class, $method, $params) {
            if($class && $method) {
                // 首字母转为大写
                $class = ucfirst($class);
                $file = $this->params['path'] . '/' . $class . '.php';
                //判断文件是否存在,如果有,则引入文件
                if(file_exists($file)) {
                    require_once $file;
                    //实例化类,并调用客户端指定的方法
                    $obj = new $class();
                    //如果有参数,则传入指定参数
                    if(!$params) {
                        $data = $obj->$method();
                    } else {
                        $data = $obj->$method($params);
                    }
                    // 打包数据
                    $this->packProtocol($data);
                    //把运行后的结果返回给客户端
                    fwrite($client, $data);
                }
            } else {
                fwrite($client, 'class or method error');
            }
        }
    
        /**
         * User: yuzhao
         * CreateTime: 2018/11/16 上午12:10
         * Description: 解析协议
         */
        private function parseProtocol($buf, &$class, &$method, &$params) {
            $buf = json_decode($buf, true);
            $class = $buf['class'];
            $method = $buf['method'];
            $params = $buf['params'];
        }
    
        /**
         * User: yuzhao
         * CreateTime: 2018/11/16 上午12:30
         * @param $data
         * Description: 打包协议
         */
        private function packProtocol(&$data) {
            $data = json_encode($data, JSON_UNESCAPED_UNICODE);
        }
    
    }
    
    RpcServer::instance([
        'host'  => '127.0.0.1',
        'port'  => 8888,
        'path'  => './api'
    ])->run();

    rpc客户端

    <?php
    /**
     * User: yuzhao
     * CreateTime: 2018/11/16 上午12:2
     * Description: Rpc客户端
     */
    class RpcClient {
    
        /**
         * User: yuzhao
         * CreateTime: 2018/11/16 上午12:21
         * @var array
         * Description: 调用的地址
         */
        private $urlInfo = array();
    
        /**
         * RpcClient constructor.
         */
        public function __construct($url)
        {
            $this->urlInfo = parse_url($url);
        }
    
        /**
         * User: yuzhao
         * CreateTime: 2018/11/16 上午12:2
         * Description: 返回当前对象
         */
        public static function instance($url) {
            return new RpcClient($url);
        }
    
        public function __call($name, $arguments)
        {
            // TODO: Implement __call() method.
            //创建一个客户端
            $client = stream_socket_client("tcp://{$this->urlInfo['host']}:{$this->urlInfo['port']}", $errno, $errstr);
            if (!$client) {
                exit("{$errno} : {$errstr} 
    ");
            }
            $data = [
                'class'  => basename($this->urlInfo['path']),
                'method' => $name,
                'params' => $arguments
            ];
            //向服务端发送我们自定义的协议数据
            fwrite($client, json_encode($data));
            //读取服务端传来的数据
            $data = fread($client, 2048);
            //关闭客户端
            fclose($client);
            return $data;
        }
    }
    $cli = new RpcClient('http://127.0.0.1:8888/test');
    echo $cli->tuzisir1()."
    ";
    echo $cli->tuzisir2(array('name' => 'tuzisir', 'age' => 23));

    提供服务的文件

    <?php
    /**
     * User: yuzhao
     * CreateTime: 2018/11/16 上午12:28
     * Description:
     */
    
    class Test {
    
        public function tuzisir1() {
            return '我是无参方法';
        }
        public function tuzisir2($params) {
            return $params;
        }
    }
  • 相关阅读:
    关闭firefox的plugincheck
    C# 三个定时器区别
    数字图像处理学习 01 图像的几何变换
    C++ dll的创建和使用
    使用Log4Cplus+配置文件打印日志
    Bmp图像的数据格式及读取
    GCC的使用和Makefile的编写
    day03 QT学习 常用控件 QLabel QPushButton QLineEdit使用 QSS介绍以及QObject子对象的遍历
    day02 QT学习 字符集和中文乱码的问题
    day01 QT学习 信号槽和QWidget介绍
  • 原文地址:https://www.cnblogs.com/tkzc2013/p/14335481.html
Copyright © 2011-2022 走看看