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
。
- 远程 program number、program version number、procedure number 唯一确定调用的过程。
- 认证、完整性和隐私:
-
调用含有两个认证字段:credential 和 verifier;回复含有 response verifier。字段定义为如下的
opaque_auth
结构体。
-
第 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 的基础上定义了 program
、procedure
、version
等关键字。示例程序如下:
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 节