分布式多媒体计算机系统
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

3.5 远程过程调用(RPC)

RPC是DCE的第二个基础工具。在分布式系统中,RPC扩展了本地程序调用机制,屏蔽了下层复杂的网络技术,使分布式应用的开发类似于单机应用。DCE RPC是RPC系统的一个典型代表,其规范得到了微软分布式计算基本系统的采用。

3.5.1 DCE RPC的目标

DCE RPC系统的目标是比较传统的。首先同时也是最重要的是,RPC系统使客户机可以通过简单的本地过程调用来访问远程服务。这种接口使得客户机程序(如应用程序)能够以一种简单的、为多数程序员所熟悉的方式来编写,还使得对大量现有的代码不需要进行改动(或者只需要极少的改动)就能够在分布式环境下运行。

RPC系统负责向客户机隐藏所有细节,并且也在某种程度上对服务器进行细节隐藏。RPC系统首先自动找到恰当的服务器,随后在客户机软件和服务器软件之间建立通信(这个过程一般称为绑定)。它还能处理双向数据传输,在必要的情况下把消息分割成片段,然后再将片段重组还原成消息(比如,在参数之一是大数组的情况下)。最后,RPC系统可以自动完成客户机和服务器间的数据类型转换,这样,可使客户机和服务器运行在体系结构不同且字节排序方式不同的机器上。

由于RPC系统具有隐藏细节的能力,所以客户机和服务器是彼此高度独立的。可以用Java编写客户机程序,而用C语言编写服务器程序;反之亦然。客户机和服务器可以运行于不同的硬件平台上,并且可使用不同的操作系统。它还支持非常多的网络协议和数据表示方式,而不需要客户机和服务器进行任何干预。

DCE的RPC由两部分组成:

(1)接口定义语言(IDL)和相关的编译器。

(2)运行库。

前者定义客户机和服务器的接口协议,指定返回值的数据类型,IDL编译后生成存根stub(客户机、服务器两方)分别与程序相连,实际运行再与运行库相连。后者主要解决:

(1)异种机之间数据不同的进程通信。

(2)支持RPC的各种执行语义。

(3)提供协议无关性、可任选协议系列。

(4)与目录服务结合找到所需的服务器。

(5)与安全服务结合,经过确认。

3.5.2 编写客户机程序和服务器程序

DCE PRC系统由许多组件组成,其中包括语言组件、库、守护程序以及工具程序等。配合使用这些组件就可以编写客户机程序和服务器程序。本节将对各个部分以及它们相互配合的方式进行描述。图3-6给出用DCE编写RPC客户机程序和服务器程序的完整过程。

图3-6 用DCE RPC编写客户机程序和服务器程序的完整过程

在客户机—服务器系统中,将各个部分结合到一起的是使用接口定义语言IDL描述的接口定义。这种语言允许以极其类似于ANSI C语言中的函数原型的形式来对过程进行说明。IDL文件也可以包含类型定义、常量声明以及正确进行参数编组、结果解编时所必需的其他信息。在理想情况下,接口定义中还应该含有过程所完成的工作的形式化定义,但是这样的定义在目前的技术条件下还无法做到。因此接口定义只是规定了调用的格式,而不包括调用的语义。编写者顶多能够加入少量注释,以描述该过程要完成的工作。

每个IDL文件中的关键部分是指定接口的全局惟一标志符。在第一个RPC消息中,客户机把该标志符发送给服务器,由服务器检验该标志符是否正确。如果当某个客户机无意中试图绑定到错误服务器或正确服务器的一个过时版本上时,服务器将会检测到该错误,绑定将不会建立。

接口定义和惟一标志符在DCE中是紧密联系在一起的。如图3-6所示,编写服务器或客户机应用程序的第一步常常是调用uuidgen程序,要求该程序生成一个原型IDL文件,其中包含一个接口标志符,该标志符保证不会在由uuidgen生成的任何其他接口中再次使用。在该标志符的编码过程中加进了它所在的位置和创建时间,从而确保了它的惟一性。该标志符是一个128位的二进制数,在IDL文件中表示为一个十六进制的ASCII字符串。

下一步是编辑IDL文件,填入远程过程名以及它们使用的参数。值得注意的是,RPC并不是完全透明的(例如,客户机和服务器无法共享全局变量),而IDL的定义规则已经保证不可能表示那些不支持的结构。

IDL文件编写完毕之后,可以调用IDL编译器来编译它。IDL编译器的输出包括下列3个文件:

(1)头文件(例如,C语言形式的interface.h)。

(2)客户机存根。

(3)服务器存根。

头文件中包含惟一标志符、类型定义、常量定义以及函数原型。应该在客户机和服务器代码中使用#include语句将该头文件包含进去。客户机存根包含供客户机程序调用的实际过程,这些过程负责参数搜集,并且将搜集到的参数打包进准备送出的消息中。随后,调用运行时系统来发送该消息。客户机存根还负责将结果值从应答中提取出来,返回给客户机。服务器存根包含一些过程,在输入的消息到达时,由服务器所在机器上的运行时系统调用这些过程,这些过程随后再调用服务器过程来完成实际操作。

接下来,由应用程序编写人员编写客户机和服务器代码。要对服务器、客户机以及双方的存根进行编译。然后,将得到的客户机代码、客户机存根的目标文件与运行时库连接起来,从而得到客户机程序的二进制可执行形式。与之相仿,将服务器代码和服务器存根的代码进行编译、连接,可以得到服务器程序的二进制可执行形式。在运行时,把客户机程序和服务器程序都启动起来,就可以正确执行应用程序。

3.5.3 将客户机绑定到服务器

为了让客户机能够调用服务器,必须先对服务器进行注册,然后服务器做好接收输入调用的准备。服务器进行了注册之后,客户机就能够对服务器进行实际定位,然后绑定到服务器。服务器定位分两步进行:

(1)定位服务器所在的机器。

(2)定位该机器上的服务器(也就是正确的进程)。

第(2)步稍微有些复杂,但基本上可以归结为这样一个问题:为了与服务器通信,客户机需要知道服务器所在机器上的一个端点(Endpoint),以便向服务器所在机器发送消息。服务器的操作系统使用端点(通常称为端口,即Port)来判别输入的消息要调用哪一个进程。在DCE中,每一台运行服务器的机器上都由DCE守护程序(RPC精灵)维护一张(服务器、端点)对列表。服务器在可以接收输入请求之前,必须先请求操作系统分配一个端点,随后通过DCE守护程序注册该端点。DCE守护程序在端点列表中记录下有关信息(包括服务器采用何种协议)供以后使用。

服务器同时还需要通过目录服务进行注册,方法是给出服务器所在机器的网络地址以及在查询该服务器时使用的名字。把客户机绑定到服务器的过程如图3-7所示。

图3-7 把客户机绑定到服务器的过程

假定客户机希望绑定到一个视频服务器上,该服务器的本地名是/local/multimedia/video/movies。客户机把该名字传递给目录服务器,目录服务器返回运行视频服务器的机器的网络地址。客户机随后向该机器上的DCE守护程序(它的端点是公开的)发出请求,要求它在端点列表中查询视频服务器使用的端点。利用所获得的信息,就可以执行RPC了。在随后执行RPC的过程中,不再需要进行查询。如果有必要,DCE还允许客户机为了查找一个合适的服务器执行较为复杂的搜索。另外,还可以选择执行安全的RPC。

3.5.4 执行RPC

实际的RPC过程是以常规方式透明地执行的。客户机存根对参数进行编组,然后把它们交给运行时库,以使用在绑定时选定的协议来传输这些参数。当消息送达服务器端的时候,系统根据输入的消息中包含的端点信息将该消息发送给相应的服务器。运行时,库将消息传递给服务器存根,由服务器存根将参数解编,然后调用服务器。应答消息的返回过程正好相反。

DCE提供了一些语义选项。默认的选择是至多一次操作(At-Most-Once Operation),在这种情况下,同一个调用的执行不能超过一次,即使系统崩溃时也是如此。在实践中,这意味着如果服务器在RPC过程中崩溃,随后又迅速恢复,客户机不再重复刚才的操作,因为担心该操作可能已经执行过一次了。

作为另一种解决方法,也可以把某个远程过程标记为幂等的(Idempotent,在IDL文件中声明),这意味着可以重复多次执行该过程,而不会造成任何不良后果。例如,从文件中读取指定的某个块的操作就可以反复尝试多次,直到成功为止。如果由于服务器崩溃而导致一个幂等的RPC失败,那么客户机可以等待服务器重启完毕,然后再次进行尝试。还有其他一些语义(但是极少使用),包括对本地网络上的所有机器进行RPC广播等。