大多数的网络程序设计都是编写一些调用系统提供的函数来完成特定的网络操作的应用程序。例如,一个函数完成 T C P的主动打开,另一个完成 T C P的被动打开,一个函数在一个T C P连接上发送数据,另一个设置特定的协议选项(如激活 T C P的k e e p a l i v e定时器)。在1 . 1 5节我们提到过两个常用的用于网络编程的函数集( A P I):插口( s o c k e t )和T L I。正像客户端和服务器端运行的操作系统可能会不相同一样,双方使用的 A P I也可能会不相同。由通信协议和应用协议决定一对客户和服务器是否可以彼此通信。如果两台主机连接在一个网络上,并且都有一个T C P / I P的实现,那么一台主机上的一个使用 C语言编写的、使用插口和 T C P的U n i x客户程序可以和另一台主机上的一个使用 C O B O L语言编写的、使用其他 A P I和T C P的大型机服务器进行通信。
一般来说,客户发送命令给服务器,服务器向客户发送应答。目前为止,我们讨论过的所有应用程序—P i n g,Tr a c e r o u t e,选路守护程序、以及 D N S、T F T P、B O O T P、S N M P、 Te l n e t、F T P和S M T P的客户和服务器—都是采用这种方式实现的。
远程过程调用RPC (Remote Procedure Call)是一种不同的网络程序设计方法。客户程序编写时只是调用了服务器程序提供的函数。这只是程序员所感觉到的,实际上发生了下面一些动作。
一个R P C程序包提供了很多好处。
R P C程序设计的细节可以参看参考文献 [Stevens 1990]的第1 8章。两个常用的 R P C程序包是Sun RPC和开放软件基金(O S F)分布式计算环境(D C E)的R P C程序包。我们对于R P C的兴趣在于想了解 Sun RPC中过程调用和过程返回报文的形式,因为本章中讨论的网络文件系统使用了它们。Sun RPC的第2版定义在RFC 1057 [Sun Microsystems 1988a]中。
Sun RPC Sun RPC 有两个版本。一个版本建立在插口A P I基础上,和 T C P和U D P打交道。另一个称为 T I - R P C的(独立于运输层),建立在TLI API基础上,可以和内核提供的任何运输层协议打交道。尽管本章中我们只讨论 T C P和U D P,从讨论的观点来看,两者是一样的。
图2 9 - 1显示的是使用 U D P时,一个R P C过程调用报文的格式。 I P首部和U D P首部是标准的首部,我们已经在图 3 - 1和图 11 - 2中显示过。 U D P首部以下是 R P C程序包定义的部分。
事务标识符( X I D)由客户程序设置,由服务器程序返回。当客户收到一个应答,它将服务器返回的 X I D与它发送的请求的 X I D相比较。如果不匹配,客户就放弃这个报文,等待从服务器返回的下一个报文。
每次客户发出一个新的 R P C,它就会改变报文的X I D。但是如果客户重传一个以前发送过的 R P C(因为它没有收到服务器的一个应答),重传报文的X I D不会修改。
调用( c a l l )变量在过程调用报文中设置为 0,在应答报文中设置为 1。当前的R P C版本是2。接下来三个变量:程序号、版本号和过程号,标识了服务器上被调用的特定过程。
证书( c r e d e n t i a l )字段标识了客户。有些情况下,证书字段设置为空值;另外一些情况下,证书字段设置为数字形式的客户的用户号和组号。服务器可以查看证书字段以决定是否执行请求的过程。验证 ( v e r i f i e r )字段用于使用了D E S加密的安全 R P C。尽管证书字段和验证字段是可变长度的字段,它们的长度也作为字段的一部分被编码。
接下来是过程参数 (procedure parameter)字段。参数的格式依赖于远程过程的定义。接收者(服务器残桩)如何知道参数字段的大小呢?既然使用的是U D P协议,U D P数据报的大小减去验证字段以上所有字段的长度就是参数的大小。如果使用的不是U D P而是T C P,因为T C P是一个字节流协议,没有记录边界,所以没有固定的长度。为了解决这个问题,在T C P首部和X I D之间增加了一个4字节的长度字段,告诉接收者这个R P C调用由多少字节组成。这也使得一个R P C调用报文在必要时可以用多个T C P段来传输(D N S使用了类似的技术,参见习题1 4 - 4)。 图2 9 - 2显示了一个R P C应答报文的格式。当远程过程返回时,服务器残桩将这个报文发送给客户残桩。
应答报文中的X I D字段是从调用报文的 X I D字段复制而来。应答字段设置为 1,以区别于调用报文。如果调用报文被接受,状态字段设置为 0(如果R P C的版本号不为2,或者服务器不能鉴别客户的身份,调用报文可能被拒绝)。安全的R P C使用验证字段来标识服务器。
如果远程过程调用成功,接受状态字段置为 0。一个非零的值可能表示一个不合法的版本号或者一个不合法的过程号。如果使用的不是 U D P而是T C P,如同R P C调用报文一样,在T C P首部和X I D字段之间插入一个4字节的长度字段。