PHP implementation creates an RPC service operation example

Time:2021-6-8

This article describes the PHP implementation of creating an RPC service operation. The details are as follows:

The full name of RPC is remote procedure call, which translates as “remote procedure call”. It is mainly used in remote communication and mutual call between different systems.

For example, there are two systems, one is written in PHP and the other is written in Java. If PHP wants to call a method of a class in Java, RPC is needed.

How to adjust it? It’s impossible to call directly. PHP can only request the service of Java through some custom protocol. Java parses the protocol, instantiates the class locally and calls the method, and then returns the result to PHP.

Here we use the socket extension of PHP to create a server and a client to demonstrate the calling process.

The code of rpcserver.php is as follows:

<?php
class RpcServer {
  protected $serv = null;

  public function __construct($host, $port, $path) {
    //Create a TCP socket service
    $this->serv = stream_socket_server("tcp://{$host}:{$port}", $errno, $errstr);
    if (!$this->serv) {
      exit("{$errno} : {$errstr} \n");
    }
    //Determine whether our RPC service directory exists
    $realPath = realpath(__DIR__ . $path);
    if ($realPath === false || !file_exists($realPath)) {
      exit("{$path} error \n");
    }

    while (true) {
      $client = stream_socket_accept($this->serv);

      if ($client) {
        //Here, for simplicity, we read it all at once
        $buf = fread($client, 2048);
        //Parsing the protocol sent by the client
        $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]);
          $file = $realPath . '/' . $class . '.php';
          //Judge whether the file exists, if so, import the file
          if(file_exists($file)) {
            require_once $file;
            //Instantiate the class and call the method specified by the client
            $obj = new $class();
            //If there are parameters, the specified parameters are passed in
            if(!$paramsRet) {
              $data = $obj->$method[1]();
            } else {
              $data = $obj->$method[1](json_decode($params[1], true));
            }
            //Return the running result to the client
            fwrite($client, $data);
          }
        } else {
          fwrite($client, 'class or method error');
        }
        //Close client
        fclose($client);
      }
    }
  }

  public function __destruct() {
    fclose($this->serv);
  }
}

new RpcServer('127.0.0.1', 8888, './service');

The code of rpcclient.php is as follows:

<?php

class RpcClient {
  protected $urlInfo = array();
  
  public function __construct($url) {
    //Resolve URL
    $this->urlInfo = parse_url($url);
    if(!$this->urlInfo) {
      exit("{$url} error \n");
    }
  }
  
  public function __call($method, $params) {
    //Create a client
    $client = stream_socket_client("tcp://{$this->urlInfo['host']}:{$this->urlInfo['port']}", $errno, $errstr);
    if (!$client) {
      exit("{$errno} : {$errstr} \n");
    }
    //Pass the class name of the call
    $class = basename($this->urlInfo['path']);
    $proto = "Rpc-Class: {$class};" . PHP_EOL;
    //Pass the method name of the call
    $proto .= "Rpc-Method: {$method};" . PHP_EOL;
    //Pass the parameters of the method
    $params = json_encode($params);
    $proto .= "Rpc-Params: {$params};" . PHP_EOL;
    //Send our custom protocol data to the server
    fwrite($client, $proto);
    //Read the data from the server
    $data = fread($client, 2048);
    //Close client
    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));

Then run the above two scripts separately (note that PHP needs to add environment variables)


> php RpcServer.php
> php RpcClient.php

The results are as follows

The test.php code is as follows:


<?php
class Test {
  public function hehe() {
    return 'hehe';
  }
  public function hehe2($params) {
    return json_encode($params);
  }
}

The directory structure is as follows:

The above custom protocol can be modified at will, as long as the client and server can be unified and parsed.

By requesting the server, the client passes the class, method and parameter to be called to the server, and the server returns the result by instantiating the calling method.

For more information about PHP, readers interested in this site can see the following topics: PHP socket usage summary, PHP string usage summary, PHP mathematical operation skills summary, PHP object-oriented programming introductory course, PHP array operation skills encyclopedia, PHP data structure and algorithm tutorial “Summary of PHP programming algorithm” and “summary of PHP network programming skills”

I hope this article is helpful for PHP programming.