# RPC，第 1 部分：远程过程调用简介

> 原文：<https://github.com/angrave/SystemProgramming/wiki/RPC%2C-Part-1%3A-Introduction-to-Remote-Procedure-Calls>

## 什么是 RPC？

远程过程调用。 RPC 是我们可以在不同的机器上执行过程（函数）的想法。在实践中，该过程可以在同一台机器上执行，但是它可以在不同的上下文中 - 例如在具有不同权限和不同生命周期的不同用户下。

## 什么是特权分离？

远程代码将在不同的用户下执行，并具有来自调用者的不同权限。实际上，远程呼叫可以以比呼叫者更多或更少的特权执行。这原则上可用于提高系统的安全性（通过确保组件以最小特权运行）。遗憾的是，需要仔细评估安全问题，以确保不会破坏 RPC 机制来执行不需要的操作。例如，RPC 实现可以隐式地信任任何连接的客户端来执行任何操作，而不是对数据子集的操作子集。

## 什么是存根代码？什么是编组？

存根代码是隐藏执行远程过程调用的复杂性的必要代码。存根代码的作用之一是 _ 将 _ 必要的数据编组成可以作为字节流发送到远程服务器的格式。

```c
// On the outside 'getHiscore' looks like a normal function call
// On the inside the stub code performs all of the work to send and receive the data to and from the remote machine.

int getHiscore(char* game) {
  // Marshall the request into a sequence of bytes:
  char* buffer;
  asprintf(&buffer,"getHiscore(%s)!", name);

  // Send down the wire (we do not send the zero byte; the '!' signifies the end of the message)
  write(fd, buffer, strlen(buffer) );

  // Wait for the server to send a response
  ssize_t bytesread = read(fd, buffer, sizeof(buffer));

  // Example: unmarshal the bytes received back from text into an int
  buffer[bytesread] = 0; // Turn the result into a C string

  int score= atoi(buffer);
  free(buffer);
  return score;
}
```

## 什么是服务器存根代码？什么是解组？

服务器存根代码将接收请求，将请求解组为有效的内存数据调用底层实现，并将结果发送回调用方。

## 你怎么发送 int？浮动？结构？链表？图表？

要实现 RPC，您需要决定（并记录）将用于将数据序列化为字节序列的约定。即使是简单的整数也有几种常见的选择：

*   签名还是未签名？
*   ASCII
*   固定的字节数或变量取决于幅度
*   小端或大端二进制格式？

要编组结构，请确定需要序列化哪些字段。可能没有必要发送所有数据项（例如，某些项可能与特定 RPC 无关，或者可以由服务器从存在的其他数据项重新计算）。

要编组链表，不必发送链接指针 - 只是流式传输值。作为解组的一部分，服务器可以从字节序列重新创建链表结构。

通过从头节点/顶点开始，可以递归地访问简单树以创建数据的序列化版本。循环图通常需要额外的内存来确保每个边和顶点只处理一次。

## 什么是 IDL（接口设计语言）？

手动编写存根代码是痛苦的，乏味的，容易出错的，难以维护的，并且难以从实现的代码中对线协议进行反向工程。更好的方法是指定数据对象，消息和服务，并自动生成客户端和服务器代码。

接口设计语言的一个现代示例是 Google 的 Protocol Buffer .proto 文件。

## RPC 与本地呼叫的复杂性和挑战？

远程过程调用明显较慢（10x 到 100x）并且比本地调用更复杂。 RPC 必须将数据编组为与线路兼容的格式。这可能需要多次通过数据结构，临时存储器分配和数据表示的转换。

强大的 RPC 存根代码必须智能地处理网络故障和版本控制。例如，服务器可能必须处理来自仍在运行存根代码的早期版本的客户端的请求。

安全 RPC 需要实现额外的安全检查（包括身份验证和授权），验证数据并加密客户端和主机之间的通信。

## 传输大量结构化数据

我们来看看三种使用 3 种不同格式传输数据的方法--JSON，XML 和 Google Protocol Buffers。 JSON 和 XML 是基于文本的协议。下面是 JSON 和 XML 消息的示例。

```text-xml
<ticket><price currency='dollar'>10</price><vendor>travelocity</vendor></ticket>
```

```source-js
{ 'currency':'dollar' , 'vendor':'travelocity', 'price':'10' }
```

Google Protocol Buffers 是一种开源高效的二进制协议，强调高吞吐量，低 CPU 开销和最小内存复制。存在多种语言的实现，包括 Go，Python，C ++和 C.这意味着可以从.proto 规范文件生成多种语言的客户端和服务器存根代码，以便将数据与二进制流进行编组。

Google Protocol Buffers 通过忽略消息中存在的未知字段来减少版本控制问题。有关更多信息，请参阅协议缓冲区简介。

[https://developers.google.com/protocol-buffers/docs/overview](https://developers.google.com/protocol-buffers/docs/overview)