Skip to content

Commit

Permalink
润色
Browse files Browse the repository at this point in the history
  • Loading branch information
lwlwilliam committed Dec 30, 2024
1 parent f3d4e8e commit e361a4d
Showing 1 changed file with 29 additions and 24 deletions.
53 changes: 29 additions & 24 deletions _posts/2024/2024-12-29-一个简单的 RPC 示例.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,31 @@ keywords: RPC,网络

远程过程调用——`RPC(Remote Procedure Call)`,在`《UNIX 网络编程》`一书中是这样描述的:被调用过程和调用过程处于不同的进程中,一个进程调用同一台主机上另一个进程的某个过程(函数)。`RPC`通常允许一台主机上的某个客户调用另一台主机上的某个服务器过程,只要这两台主机以某种形式的网络连接着。

`RPC`的实现方式有很多,如`XML-RPC``JSON-RPC``SOAP`等,这里我们使用`JSON`作为数据传输格式,`TCP`作为网络传输协议,`PHP`作为编程语言。具体传输格式如下:

```json
{
"class": "Test",
"method": "say",
"params": ["william", "你好,世界"]
}
```

为了简化示例,代码仅能调用类方法,通过`class`指定类,`method`指定方法名,`params`指定参数。

### RPC 服务端

`Test`是示范服务端中被客户端调用的类`RPCServer`用于接收`RPCClient`请求并解释、代替客户端调用类方法。
`Test`是服务端中可被客户端调用的类`RPCServer`用于接收`RPCClient`请求并解释、代替客户端调用类方法。

```php
<?php
// RPCServer.php

class Test
{
public function say(string $name, string $message): string
public function say(string $name, string $message, mixed ...$extra): string
{
return "$name: $message";
}

public function hello(): string
{
return 'Hello world';
return "$name: $message". "\t(". json_encode([...$extra], JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE). ")";
}
}

Expand Down Expand Up @@ -62,7 +69,7 @@ class RPCServer
$res = $obj->{$method}(...$json['params']);
fwrite($client, json_encode($res));
} catch (Throwable $e) {
fwrite($client, $e->getMessage());
fwrite($client, '"'. $e->getMessage(). '"');
}
} else {
fwrite($client, '"method not exist"');
Expand Down Expand Up @@ -98,20 +105,16 @@ $ php RPCServer.php

### RPC 客户端

`Test`是一个伪类,主要作用就是提供`IDE`提示,其中的文档注释对代码开发特别友好,实际上去掉也不影响功能完整性;`RPCClient`作为代理,发起远程过程调用;`Factory`起到隐藏网络细节的作用,让用户误以为这只是一个本地的调用
`Test`只是一个伪类,作用就是提供`IDE`提示,其中的文档注释对开发友好,实际上去掉也不影响功能完整性;`RPCClient`作为代理,发起远程过程调用;`Factory`起到隐藏网络细节的作用,让用户以为这只是一个本地的调用

```php
<?php
// RPCClient.php

/**
* @method string say(string $param1, string $param2)
* @method string hello()
* @method string say(string $param1, string $param2, mixed ...$extra)
*/
class Test
{

}
class Test {}

class RPCClient
{
Expand All @@ -131,7 +134,6 @@ class RPCClient
*/
function __call(string $method, $params)
{
// 创建一个客户端
$client = stream_socket_client("tcp://$this->host:$this->port", $errno, $error);
if (!$client) {
throw new Exception("$errno: $error");
Expand Down Expand Up @@ -162,17 +164,20 @@ class Factory
* @var Test $test
*/
$test = Factory::create('Test');
$res = $test->say('william', '你好,世界');
var_dump(json_decode($res));
$res = $test->say('william', '你好,世界', ['数组', ['name' => 'william']], 'extra');
var_dump(json_decode($res)); // string(66) "william: 你好,世界 ([["数组",{"name":"william"}],"extra"])"
$res = $test->say('william');
var_dump(json_decode($res)); // string(139) "Too few arguments to function Test::say(), 1 passed in /usr/share/php/RPCServer.php on line 43 and exactly 2 expected"
$res = $test->say();
var_dump(json_decode($res)); // string(139) "Too few arguments to function Test::say(), 0 passed in /usr/share/php/RPCServer.php on line 43 and exactly 2 expected"
$res = $test->hello();
var_dump(json_decode($res));
$res = $test->world();
var_dump(json_decode($res));
var_dump(json_decode($res)); // string(16) "method not exist"
```

```bash
$ php RPCClient.php
string(24) "william: 你好,世界"
string(11) "Hello world"
string(66) "william: 你好,世界 ([["数组",{"name":"william"}],"extra"])"
string(139) "Too few arguments to function Test::say(), 1 passed in /usr/share/php/RPCServer.php on line 43 and exactly 2 expected"
string(139) "Too few arguments to function Test::say(), 0 passed in /usr/share/php/RPCServer.php on line 43 and exactly 2 expected"
string(16) "method not exist"
```

0 comments on commit e361a4d

Please sign in to comment.