ONC远程过程调用



1. 简介
本文描述了ONC远程过程调用使用的报文协议。报文协议用XDR语言描述。本文假定读者熟悉XDR语言。

2. 术语

每个远程过程调用有两方面:活跃客户端发出请求,服务器端给出回答。一个网络服务是一个或多个远程程序的集合。远程程序实现一个或多个远程过程;这些过程及其参数、结果由特定的程序协议记录。服务器可能支持多个版本的远程程序以与变化的协议兼容。

例如,网络文件服务可能由两个程序组成。一个程序用于处理高级应用,如文件系统读写控制和锁。另一个程序处理低级文件输入和输出。网络文件服务的客户端将调用这两个程序。

客户端和服务器端只应用与特定的事务中;硬件实体和软件实体在不同时刻可以扮演不同角色。如,一个远程服务程序也可以是网络文件服务的客户端。

3. RPC模型

ONC RPC协议基于远程过程调用模型,类似于本地过程调用模型。在本地过程调用模型中,调用者把过程的参数放在特定的位置。接着,它把控制传给过程,过程的结 果可以从特定的位置得到,调用者继续执行。远程过程调用模型也是类似的。控制在两个进程中传递:调用者进程和服务器进程。调用者进程首先向服务器进程发出 请求报文,然后等待回答。调用报文包括过程的参数,回答报文包括过程的结果。一旦接收到应答报文,就可获取过程的结果,调用者继续执行。

在服务器端,一个进程睡眠等待调用报文的到来。当有调用报文时,服务器进程提取过程的参数,计算出结果,发送应答报文,接着等待下一条报文。

在 这种模型中,在任一时刻最多只有一个进程时活跃的。但这种模型只是一个例子。ONC RPC协议对于并发模型没有限制。例如,可以有填补的RPC调用,这样,客户端在等待服务器回答时可以更有效的工作。另一种作法是在服务器端开辟一个新的 任务处理到来的调用,这样服务器还可以处理其它的请求。

远程过程调用和本地过程调用有以下不同:

错误处理:远程过程调用中必须处理远程服务器和网络错误。
全局变量:由于服务器端不能读写客户端的地址空间,隐含参数不能作为全局变量传递。
效率:远程过程比本地过程慢。
认证:由于远程过程调用可以在不安全的网络上传递,认证就是必须的。认证防止一个实体被冒充成另一个实体。
结论:尽管有工具可以自动为特定服务产生客户端和服务器端的库文件,协议仍需仔细设计。

4. 传输和语义

RPC 协议可以在不同传输协议上实现。RPC不限制报文是如何从一个进程传递到另一个进程,但对报文规范和解释有限制。应用程序可能希望得到传输层的信息。如, 传输协议可能对RPC报文的大小有限制,也可能是面向流的,如TCP,对 报文的大小没有限制。客户端和服务器端必须在协议的选择上取得一致。

必须指出RPC没有实现任何的可靠性。应用程序必须重视RPC下的传输协议。如果RPC运行在可靠传输的基础上,如TCP,大部分工作就已完成。如果运行在不可靠协议的基础上,如UDP,它就必须自己实现RPC中未支持的超时,重传,重复检测策略。

由 于传输的独立性,RPC协议没有在日常过程中附加特定的语义。语义可以从下层的传输协议中得到。例如,RPC运行在不可靠传输协议上,如UDP。如果应用 程序超时后重传RPC调用报文,但没有得到回答,它就不能推断出程序执行次数的信息。当它收到应答后,就可推断出程序至少被执行了一次。

服 务器可能希望记住先前客户端的请求,以保证最多执行一次的语义。服务器可以通过在每个RPC报文中加上一个事务ID域来实现。事务ID域主要用于客户端实 体对调用应答的匹配上。客户端应用还可以在重传一个调用时使用相同的事务ID。服务器可以在执行完一个调用后记录这个ID,然后不再执行相同ID的调用, 以实现最多执行一次的语义。除非检测是否相同,服务器不能使用这个ID。

另一方面,如果使用可靠传输,如TCP,应用可以从应答报文中推 断程序只执行了一次,但如果它没有收到应答报文,它不能推出远程过程没有被执行。注意即使使用了面向连接的协议,如TCP,应用仍需超时和重连以处理服务 器崩溃。除了数据报和面向连接的协议,还有其它的传输协议。如,请求-应答协议如VMTP也是可以的。ONC RPC使用TCP和UDP传输协议。

5. 绑定和会晤的独立性

客 户端和服务的绑定,传输参数不是RPC协议的一部分。这个重要而必须的功能由上层软件实现。开发者可能认为RPC协议是网络的跳转子程序指令(JSR), 绑定者使JSR有用,而且绑定者使用JSR完成自身的任务。同样的,绑定软件使RPC有用,而且使用RPC完成自身的任务。

6. 认证

RPC协议提供了使客户端与服务、调用、应答报文互相识别的域。安全和读写控制机制可以建立在报文认证基础之上。它支持几个认证协议。RPC头中有一个域指出使用了哪个协议。

7. RPC协议的需求

RPC协议提供以下内容:

调用过程的唯一规范
匹配请求和应答报文的机制
调用者和服务的互相认证
除了这些需求,以下特性也需要支持:

RPC协议的错误匹配
远程程序协议版本的错误匹配
协议错误(如过程参数的错误声明)
远程认证失败的原因
目标过程没有被调用的其它原因
7.1 RPC程序和过程

RPC 调用报文有三个无符号整数域:远程程序序号、远程程序版本号、远程过程序号,它们唯一指出被调用的过程。程序序号由中心权威管理。一旦开发者有了程序序 号,就可以实现远程程序;最初版本号通常为1。调用报文的版本域指出调用者使用哪个版本的协议。版本号使在同一服务器进程中同时支持新旧协议成为可能。过 程序号指出被调用的过程。这些序号在程序协议规范中记录。例如,文件服务协议规范记录序号为5的过程使“读”,序号为12的过程是“写”。远程程序协议可 能有几个版本,RPC报文协议也可能改变。因此,调用报文同样包括RPC版本号。应答报文包含了足够的信息来识别以下错误:

RPC的远程实现不支持版本2的协议。支持的最高、最低版本号被返回。
远程系统的远程程序不可用。
远程程序不支持所要求的版本号。最高和最低远程程序版本号被返回。
请求的过程序号不存在。(这通常是客户端协议或程序错误)
远程过程的参数不可用。(这通常是客户和服务器的协议不匹配)
7.2 认证

调用者和服务的互相认证被提供为RPC协议的一部分。调用报文包含两个认证域,凭证和确认。应答报文包含一个认证域,应答确认。RPC协议规范定义这三个域为以下不透明类型(使用XDR语言)

enum auth_flavor {

AUTH_NONE = 0,

AUTH_SYS = 1,

AUTH_SHORT = 2

/*还可有更多*/

};

 

struct opaque_auth {

auth_flavor flavor;

opaque body<400>;

};

 

换而言之,任何“opaque_auth”结构是一个对于RPC不透明(不可解释)的400字节的枚举类型“auth_flavor”。认证域数据的解释和语义由独立认证协议所规范。如果认证参数被拒绝,应答报文包含拒绝的原因。

7.3 程序序号的指定

程序序号由16进制20000000(10进制536870912)指定,如下所示:

0 - 1fffffff defined by rpc@sun.com

20000000 - 3fffffff defined by user

40000000 - 5fffffff transient

60000000 - 7fffffff reserved

80000000 - 9fffffff reserved

a0000000 - bfffffff reserved

c0000000 - dfffffff reserved

e0000000 - ffffffff reserved

第一组是由 rpc@sun.com管理的序号范围,在所有站点都必须相同。第二组是特定于站点的应用的范围。这组主要被用于跟踪新程序。当一个站点开发出一个通用应用,这个应用应在第一组中指定一个序号。开发者可以向 rpc@sun.com发邮件来申请RPC程序序号。第三组应用动态产生程序序号的应用。最后一组被将来的应用所保留,不能被使用。

7.4 RPC协议的其它应用

用于远程过程调用。通常,每个调用报文都与一个应答报文匹配。

7.4.1 批处理

当客户端希望向服务器端发送大量调用报文时非常有用。批处理通常使用可靠字节流协议传输(如TCP)。批处理中,客户端不等待服务器端的回答,服务器也不向客户端发应答。批处理调用通常在合法远程过程调用操作完成后结束。

7.4.2广播远程过程调用

广播协议中,客户端向网络发送调用并等待回答。这需要基于包的协议(如UDP)作为传输协议。支持广播协议的服务器只有在成功完成调用后才发送应答,遇到错误时保持沉默。但这根据应用而不同。广播RPC的规则也适用于多点传输棗一个RPC请求被发送到多个地址。

8. RPC报文协议

用XDR语言定义的RPC报文:

enum msg_type {

CALL = 0,

REPLY = 1

};

对调用的应答报文有两种形式:接受或拒绝。

enum reply_stat {

MSG_ACCEPTED = 0,

MSG_DENIED = 1

};

假定调用报文都被接受,以下是一个远程过程调用的可能状态:

enum accept_stat {

SUCCESS = 0, /* RPC成功执行 */

PROG_UNAVAIL = 1, /* 远程不支持程序 */

PROG_MISMATCH = 2, /* 远程不支持版本号 */

PROC_UNAVAIL = 3, /* 程序不支持过程 */

GARBAGE_ARGS = 4, /* 过程不能解析参数 */

SYSTEM_ERR = 5 /* 类似内存分配的错误 */

};

远程过程调用被拒绝的原因:

enum reject_stat {

RPC_MISMATCH = 0, /* RPC version number != 2 */

AUTH_ERROR = 1 /* remote can't authenticate caller */

};

认证失败的原因:

enum auth_stat {

AUTH_OK = 0, /* success */

/*

* failed at remote end

*/

AUTH_BADCRED = 1, /* bad credential (seal broken) */

AUTH_REJECTEDCRED = 2, /* client must begin new session */

AUTH_BADVERF = 3, /* bad verifier (seal broken) */

AUTH_REJECTEDVERF = 4, /* verifier expired or replayed */

AUTH_TOOWEAK = 5, /* rejected for security reasons */

/*

* failed locally

*/

AUTH_INVALIDRESP = 6, /* bogus response verifier */

AUTH_FAILED = 7 /* reason unknown */

};

 

RPC报文:

所 有的报文都以事务ID,xid,开始,后跟一个联合(union)。联合的判别式是msg_type,它转换成两种报文类型之一。REPLY报文的xid 总是与初始的CALL报文相匹配。注意:xid域只被客户端用于应答报文与调用报文的匹配或服务器端检测重传;服务器端不能把xid当成序号。

struct rpc_msg {

unsigned int xid;

union switch (msg_type mtype) {

case CALL:

call_body cbody;

case REPLY:

reply_body rbody;

} body;

};

RPC调用的结构:

RPC版本2协议规范中,rpcvers必须等于2。prog、vers、proc域确定远程程序,它的版本号,以及内部的过程。这些域后是两个认证参数:cred(认证凭证)和verf(认证确认)。

认证确认的目的是确认认证凭证。注意这两项虽然分开,但逻辑上是一个实体。

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 */

};

 

PRC调用的应答体:

union reply_body switch (reply_stat stat) {

case MSG_ACCEPTED:

accepted_reply areply;

case MSG_DENIED:

rejected_reply rreply;

} reply;

 

被服务器接受的RPC调用的应答:

即 使调用被接受,仍可能有错。第一个域是由服务器产生的认证确认,以便对客户端确认自身。接着是一个联合,联合的判别式是枚举accept_stat。联合 的SUCCESS分支是特定于协议的。联合的PROG_UNAVAIL、 PROC_UNAVAIL、GARBAGE_ARGS和SYSTEM_ERR分支为void。PROG_MISMATCH分支指出服务器支持的远程程序最 高和最低版本号。

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;

};

被服务器拒绝的RPC调用的应答:

调用被拒绝有两个理由:服务器端运行一个不兼容的RPC协议(RPC_MISMATCH)或服务器拒绝调用者(AUTH_ERROR)。若RPC版本不兼容,服务器返回所支持的RPC最高和最低版本号。若为非法认证,返回失败状态。

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;

};

 

9. 认证协议

如 前所述,认证参数是不透明的,但对RPC协议的其余部分是无限制的。本节定义两种标准的认证flavor。开发者可以发明新的认证类型,只要遵从 flavor号指定规则。凭证和确认的flavor指opaque_auth结构中的flavor域。flavor号,与RPC程序序号相似,被集中控 制。开发者可以向rpc2sun.com发邮件来申请新的flavor号。空认证是强制性的,它必须被实现。系统认证应尽可能地实现,许多应用使用这种认 证,实现后能增强互用性。

9.1 空认证

许多调用中,并不在意客户端的身份。这时,RPC报文的凭证、确认和应答确认的flavor是“AUTH_NONE”。未定义与“AUTH_NONE”协调的透明数据。建议透明数据长度为0。

10. 记录标志标准

当RPC 报文在字节流传输协议(如TCP)之上传输时,有必要把一个报文与另一个报文分隔开,以便检测和恢复协议错误。这被称为记录标志(RM)。一个RPC报文 与一个RM记录相匹配。一个记录由一个或多个片段组成。一个记录片段是四字节头加0到1个字节的片段数据。字节被编码成无符号二进制数,字节顺序从高到 低。数字有两个值:一个布尔型值表示这是否是记录的最后片段(若是,为1);一个31位无符号数,表示片段数据的长度。布尔型为头的高位。(注意这种记录 规则不包含在SDR标准格式中)

11. RPC语言

如同有必要用正式语言描述XDR数据类型一样,也有必要用正式语言描述操作这些XDR数据类型的过程。RPC语言是XDR语言的控制扩展,以下是这种语言的精华。

11.1 RPC语言的服务例子

ping程序的例子:

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 */

第 一个版本是带有两个过程PINGPROC_NULL和PINGPROC_PINGBACK的PING_VERS_PINGBACK。 PINGPROC_NULL不要参数,不返回结果,它在计算客户端与服务器之间的往返次数时有用。约定,任何RPC协议的0号过程应有相同的语义,不需要 任何类型的认证。第二个过程由客户端使用,让服务器ping客户端,返回操作所用的时间。下一版本,PING_VERS_ORIG,是协议的最初版本,不 包括PINGPROC_PINGBACK过程。它与旧的客户端程序兼容。

11.2 RPC语言规范

RPC语言与XDR语言一样在RFC1014中定义,除了一下不同。

program-def:

"program" identifier "{"

version-def

version-def *

"}" "=" constant ";"

 

version-def:

"version" identifier "{"

procedure-def

procedure-def *

"}" "=" constant ";"

 

procedure-def:

type-specifier identifier "(" type-specifier

("," type-specifier )* ")" "=" constant ";"

 

11.3 句法的注意事项

有两个保留字:“program”和“version”。
一个程序定义中不能出现两次版本名或版本号。
在一个版本的定义中,过程名称至多只能出现一次。
程序标识与常量和类型标识在同一空间中。
只有无符号常数才能被附值给程序,版本和过程。 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值