zoukankan      html  css  js  c++  java
  • 使用PHP来简单的创建一个RPC服务

    RPC全称为Remote Procedure Call,翻译过来为"远程过程调用"。主要应用于不同的系统之间的远程通信和相互调用。

    比如有两个系统,一个是PHP写的,一个是JAVA写的,而PHP想要调用JAVA中的某个类的某个方法,这时候就需要用到RPC了。

    怎么调?直接调是不可能,只能是PHP通过某种自定义协议请求JAVA的服务,JAVA解析该协议,在本地实例化类并调用方法,然后把结果返回给PHP。

    这里我们用PHP的socket扩展来创建一个服务端和客户端,演示调用过程。

    RpcServer.php代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    <?php
    class RpcServer {
        protected $serv = null;
     
        public function __construct($host$port$path) {
            //创建一个tcp socket服务
            $this->serv = stream_socket_server("tcp://{$host}:{$port}"$errno$errstr);
            if (!$this->serv) {
                exit("{$errno} : {$errstr} ");
            }
            //判断我们的RPC服务目录是否存在
            $realPath realpath(__DIR__ . $path);
            if ($realPath === false || !file_exists($realPath)) {
                exit("{$path} error ");
            }
     
            while (true) {
                $client = stream_socket_accept($this->serv);
     
                if ($client) {
                    //这里为了简单,我们一次性读取
                    $buf fread($client, 2048);
                    //解析客户端发送过来的协议
                    $classRet = preg_match('/Rpc-Class:s(.*); /i'$buf$class);
                    $methodRet = preg_match('/Rpc-Method:s(.*); /i'$buf$method);
                    $paramsRet = preg_match('/Rpc-Params:s(.*); /i'$buf$params);
                     
                    if($classRet && $methodRet) {
                        $class = ucfirst($class[1]);
                        $file $realPath '/' $class '.php';
                        //判断文件是否存在,如果有,则引入文件
                        if(file_exists($file)) {
                            require_once $file;
                            //实例化类,并调用客户端指定的方法
                            $obj new $class();
                            //如果有参数,则传入指定参数
                            if(!$paramsRet) {
                                $data $obj->$method[1]();
                            else {
                                $data $obj->$method[1](json_decode($params[1], true));
                            }
                            //把运行后的结果返回给客户端
                            fwrite($client$data);
                        }
                    else {
                        fwrite($client'class or method error');
                    }
                    //关闭客户端
                    fclose($client);
                }
            }
        }
     
        public function __destruct() {
            fclose($this->serv);
        }
    }
     
    new RpcServer('127.0.0.1', 8888, './service');

    RpcClient.php代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    <?php
     
    class RpcClient {
        protected $urlInfo array();
         
        public function __construct($url) {
            //解析URL
            $this->urlInfo = parse_url($url);
            if(!$this->urlInfo) {
                exit("{$url} error ");
            }
        }
         
        public function __call($method$params) {
            //创建一个客户端
            $client = stream_socket_client("tcp://{$this->urlInfo['host']}:{$this->urlInfo['port']}"$errno$errstr);
            if (!$client) {
                exit("{$errno} : {$errstr} ");
            }
            //传递调用的类名
            $class basename($this->urlInfo['path']);
            $proto "Rpc-Class: {$class};" . PHP_EOL;
            //传递调用的方法名
            $proto .= "Rpc-Method: {$method};" . PHP_EOL;
            //传递方法的参数
            $params = json_encode($params);
            $proto .= "Rpc-Params: {$params};" . PHP_EOL;
            //向服务端发送我们自定义的协议数据
            fwrite($client$proto);
            //读取服务端传来的数据
            $data fread($client, 2048);
            //关闭客户端
            fclose($client);
            return $data;
        }
    }
     
    $cli new RpcClient('http://127.0.0.1:8888/test');
    echo $cli->hehe();
    echo $cli->hehe2(array('name' => 'test''age' => 27));

    然后分别运行上面两个脚本(注意,php要添加环境变量)

    1
    2
    > php RpcServer.php
    > php RpcClient.php

    结果如下:

    Test.php代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <?php
    class Test {
        public function hehe() {
            return 'hehe';
        }
        public function hehe2($params) {
            return json_encode($params);
        }
    }

    目录结构如下:

    上面我们自定义的协议,可以随意修改,只要是客户端和服务端两边能够统一并能解析。

    客户端通过请求服务端,把要调用的类,方法和参数传递给服务端,服务端去通过实例化调用方法返回结果。

  • 相关阅读:
    URAL——DFS找规律——Nudnik Photographer
    URAL1353——DP——Milliard Vasya's Function
    URAL1203——DPor贪心——Scientific Conference
    递推DP HDOJ 5389 Zero Escape
    区间DP UVA 1351 String Compression
    树形DP UVA 1292 Strategic game
    Manacher HDOJ 5371 Hotaru's problem
    同余模定理 HDOJ 5373 The shortest problem
    递推DP HDOJ 5375 Gray code
    最大子序列和 HDOJ 1003 Max Sum
  • 原文地址:https://www.cnblogs.com/liliuguang/p/11075685.html
Copyright © 2011-2022 走看看