Skip to content

RFC 5531 - RPC: Remote Procedure Call Protocol Specification Version 2

RFC 建议阅读一些背景文献:

The paper by Birrell and Nelson [XRPC] is recommended as an excellent background for the remote procedure call concept.

RPC 不对传输层协议做要求。

  • 如果传输层不可靠,则需要实现超时、重传等机制,RPC 不提供这些服务。
  • 如果传输层可靠,则不需要做其他工作。即使如此,应用也可能需要实现超时、重连等机制以应对服务器崩溃等情况。

因此无法推断远程过程的状态,比如发送两次请求但没有收到回复,不能确定远程过程是否执行了两次。如果收到一次回复,只能确定远程过程执行了至少一次。

每个 RPC 消息都有事务 ID,一方面用于客户端匹配回复与对应的函数调用,另一方面方便服务器实现最多执行一次的语义(execute-at-most-once semantics)。

第 8 章讲述 RPC 对实现的要求:

  • RPC 程序和过程:
    • 远程 program number、program version number、procedure number 唯一确定调用的过程。
      • program number 其中一部分由 IANA 分配。有点类似于 IP 地址范围,开发者可以定义一部分本地使用的 program number。
      • procedure number 由特定程序的文档描述。
    • RPC version number 在本文中为 2
  • 认证、完整性和隐私:
    • 调用含有两个认证字段:credential 和 verifier;回复含有 response verifier。字段定义为如下的 opaque_auth 结构体。

      enum auth_flavor {
         AUTH_NONE       = 0,
         AUTH_SYS        = 1,
         AUTH_SHORT      = 2,
         AUTH_DH         = 3,
         RPCSEC_GSS      = 6
         /* and more to be defined */
      };
      
      struct opaque_auth {
         auth_flavor flavor;
         opaque body<400>;
      };
      

第 9 章描述 RPC 消息的具体结构,一些重要的部分摘录如下。结合前文的叙述,这些结构一目了然,不需要进一步解释。

enum msg_type {
   CALL  = 0,
   REPLY = 1
};

enum accept_stat {
   SUCCESS       = 0, /* RPC executed successfully       */
   PROG_UNAVAIL  = 1, /* remote hasn't exported program  */
   PROG_MISMATCH = 2, /* remote can't support version #  */
   PROC_UNAVAIL  = 3, /* program can't support procedure */
   GARBAGE_ARGS  = 4, /* procedure can't decode params   */
   SYSTEM_ERR    = 5  /* e.g. memory allocation failure  */
};

struct rpc_msg {
   unsigned int xid;
   union switch (msg_type mtype) {
   case CALL:
      call_body cbody;
   case REPLY:
      reply_body rbody;
   } body;
};

struct call_body {
   unsigned int rpcvers;       /* must be equal to two (2) */
   unsigned int prog;
   unsigned int vers;
   unsigned int proc;
   opaque_auth cred;
   opaque_auth verf;
   /* procedure-specific parameters start here */
};

union reply_body switch (reply_stat stat) {
case MSG_ACCEPTED:
   accepted_reply areply;
case MSG_DENIED:
   rejected_reply rreply;
} reply;

struct accepted_reply {
   opaque_auth verf;
   union switch (accept_stat stat) {
   case SUCCESS:
      opaque results[0];
      /*
       * procedure-specific results start here
       */
    case PROG_MISMATCH:
       struct {
          unsigned int low;
          unsigned int high;
       } mismatch_info;
    default:
       /*
        * Void.  Cases include PROG_UNAVAIL, PROC_UNAVAIL,
        * GARBAGE_ARGS, and SYSTEM_ERR.
        */
       void;
    } reply_data;
};

union rejected_reply switch (reject_stat stat) {
case RPC_MISMATCH:
   struct {
      unsigned int low;
      unsigned int high;
   } mismatch_info;
case AUTH_ERROR:
   auth_stat stat;
};

第 12 章描述 RPC 语言,其实就是在 XDR 的基础上定义了 programprocedureversion 等关键字。示例程序如下:

program PING_PROG {
      /*
       * Latest and greatest version
       */
      version PING_VERS_PINGBACK {
         void
         PINGPROC_NULL(void) = 0;
         /*
          * Ping the client, return the round-trip time
          * (in microseconds).  Returns -1 if the operation
          * timed out.
          */
         int
         PINGPROC_PINGBACK(void) = 1;
      } = 2;

      /*
       * Original version
       */
      version PING_VERS_ORIG {
         void
         PINGPROC_NULL(void) = 0;
      } = 1;
   } = 1;

   const PING_VERS = 2;      /* latest version */

这段样例程序展示了两个版本的 RPC 程序。其中新的版本增加了一个 PINGPROC_PINGBACK 过程。通过 RPC 调用中的 vers 字段,就能实现不同版本程序的兼容。

RFC 的剩余部分主要是已分配的 program number。其中比较重要的有:

# Description/Owner        RPC Program Number        Short Name
# -----------------------------------------------------------------
nfs                                100003    nfs   
NFS Automount File System          100099    autofs
NFS ACL Service                    100227    nfs_acl
rdmaconfig                         100417    rpc.rdmaconfig

Implementing Remote Procedure Calls

这是一篇 1984 年发表在 ACM 上的文章。在那时,Linux 还没有出现,RPC 在文章中也是一种实验性的新技术。这篇文章主要讲述研究者实现 RPC 时的一些考虑和决策。

  • 不实现共享内存空间,因为实现带来的复杂性和不稳定性远远超过了好处。

阅读到 1.5 节