第十章 分布式 COM ( DCOM )
1 、 DCOM
COM 的进程透明特性表现在组件对象和客户程序即可以拥有各自的进程空间,也可以共享同一个进程空间, COM 负 责把客户的调用正确传到组件对象中,并保证参数传递的正确性。组件对象和客户代码不必考虑调用传递的细节,只要按照一般的函数调用的方式实现即可。如果进 一步拓展进程透明特性,考虑组件对象与客户程序运行在不同计算机上的情形,把进程透明性拓展为位置透明性,形成分布式组件对象模型,简称为 DCOM 。
DCOM 是 COM 的扩展,它可以支持不同计算机上组件对象与客户程序之间或者组件对象之间的相互通信,这些计算机可以在局域网内、广域网上、 Internet 上。对于客户程序而言,组件程序所处的位置是透明的,我们不必编写任何处理远程调用的代码,因此, DCOM 也是 COM 的无缝扩展。 DCOM 处理了底层网络协议的所有细节。
2 、从 COM 转向 DCOM
进程内组件与客户程序之间的通信过程比较简单。本地进程外组件与客户程序之间的通信并不是直接进行的,而是用到了操作系统支持的一些跨进程通信方法。
DCOM 只是简单地把本地跨进程通信用一个网络协议传输过程来代替,只是中间数据传递的路线更长一些。当然,网络通信比单机系统环境下的跨进程通信要脆弱得多,所以为了保证协作过程的可靠性以及程序对异常事件的应变能力,客户程序和组件程序需要考虑更多的细节。
3 、 DCOM 对象的定位
客户程序调用 COM 库的基础创建函数(比如 CoGetClassObject )创建远程组件对象需要知道远程机器名和对象 CLSID 。
有两种方法可以得到远程对象的机器名信息:一是在创建函数的参数中指定 COSERVERINFO 结构,二是使用 DCOM 配置工具指定远程机器名。
COM 库的创建函数得到了远程对象的位置信息后,再把对象创建的任务交给 SCM ,由 SCM 通过 RPC 与远程机器进行通信。 SCM (程序名为 Rpcss.exe )也是 COM 库的一部分,但它是一个单独的进程。 SCM 负责创建新的 COM 对象,也负责建立组件对象与客户程序之间的连接。如果要创建远程对象,它会通过 RPC 调用远程机器上的 SCM ,由远程机器上的 SCM 启动组件进程,并创建组件对象,然后返回到客户机器。
当然,远程组件对象被创建之后,它在返回到客户机器的途中,还要经过列集和散集的处理,包括创建代理对象和装载存根代码等,这些处理与本地进程外组件对象的处理完全一致。一旦组件对象被创建完成之后,客户与组件之间的通信不再经过 SCM ,而是直接通过代理对象和存根对象以及 COM 库提供的底层传输机制来完成。
4 、列集与散集
列集与散集是实现 COM 组件对象跨进程特性的关键技术,它包括标准列集法和自定义列集法。同样的技术也适用于 DCOM 组件对象与客户程序之间的通信,两者的区别在于列集数据包的传递方式有所不同,对于本地组件对象使用 LPC 传递,而对于 DCOM 组件对象使用 RPC 传递。
DCOM 提供了一套复杂的列集和散集机制,它建立在 RPC 的基础上。由于 RPC 被定义为 DCE (分布式计算系统)标准的一部分,而 DCE RPC 定义了所有常用数据类型的数据表达方式,即网络数据表示法( NDR , network data representation )。为了使存根代码和代理对象能够正确地对参数和返回结果进行列集和散集,它们应该使用一致的数据表示法 NDR ,以便在不同的操作系统环境下也能够远程调用。
5 、对象 RPC
DCOM 协议也被称为对象 RPC ( ORPC , object remote procedure call ),它建立在 DCE RPC 协议的基础上,可用于各种基于组件的分布式系统。 ORPC 建立了一套面向对象的远程调用规范,指定了如何在网络上进行调用、对对象的引用如何表示和如何维护。 ORPC 协议已经被作为 Internet 草案递交到 IETF ( Internet Engineering Task Force , Internet 工程部)。
在 Internet 或 Intranet 网络环境下, ORPC 仍使用标准的 RPC 数据包,附加上专用于 DCOM 的一些信息――接口指针标识符( IPID , interface point identifier )、版本信息和扩展信息――作为调用和返回的附加参数进行传送,其中 IPID 表示调用被处理的远程机器上特定对象的特定接口。 DCOM 客户程序必须周期性地“ pinging ”远程机器上的对象,以便保证客户与对象一直处于连接状态。
6 、 DCOM 特性
DCOM 可以作为分布式应用系统的基本架构,客户程序与 DCOM 组件对象之间形成了客户/服务器关系,进一步可构成多层软件模型。 DCOM 组件具有 COM 组件的一些基本特性,包括重用性、语言无关性等。而位置透明性 是 DCOM 的一个基本特性。 DCOM 的其他特性如下:
( 1 )可伸缩性。一方面, DCOM 利用操作系统本身的可伸缩性;另一方面, DCOM 提供了灵活的配置方案,允许不同的组件对象允许在不同的服务器上, DCOM 的位置透明性保证了这种变化可以不必修改组件源程序。
( 2 )可配置性。安装和管理是分布式软件系统的两个重要环节。 DCOM 提供了一个图形界面的配置工具程序( DCOMCNFG.EXE ),可使客户程序和组件程序在不改变代码的情况下适应不同的网络环境。
( 3 )安全性。 DCOM 使用了 Windows NT 提供的可扩展安全性框架,在非 NT 平台上实现的 DCOM 也包括了一个与 NT 兼容的安全提供器。 DCOM 实现的安全性分为访问安全性和激活安全性,访问安全性指定那些用户可以调用组件对象,激发安全性指定哪些用户可以在一个新进程中创建新的对象。
( 4 )协议无关性。
( 5 )平台独立性
7 、对象激活
激活( activation )一个组件对象包括两种情形:一是创建新的组件对象,二是建立已有组件对象与客户之间的连接。
COM 扩展到 DCOM 之后,远程对象的创建过程有所不同。为了标识一个远程对象,仅仅提供一个 128 位的 GUID 还不够,还必须提供远程对象所在的机器名,也称为远程服务器名“ RemoteServerName ”。
( 1 )创建 DCOM 组件方法一
通过 DCOM 配置工具指定远程服务器名,这种方式使得 DCOM 组件具有位置透明性。在 Windows 系统平台上,远程服务器名字 RemoteServerName 值被保存在系统注册表 HKEY_CLASSES_ROOT/APPID 键下。
从 CLSID 和 AppID 键的结构可以看出,每个 AppID 可用于多个组件对象,通常它代表了由多个 CLSID 共享的进程,该进程中的所有对象共享同样的配置信息,包括远程服务器名以及安全信息。在 DCOM 中引入 AppID 概念可以避免太多的注册表关键字。
( 2 )创建 DCOM 组件方法二
用第一种方法并不是总能满足应用的要求,有些应用要求在程序运行过程中控制要连接的服务器,比如多人游戏程序、网络远程管理工具等。对于这样的应用, DCOM 允许在创建函数中指定远程服务器名字。可以指定远程服务器名字的创建函数: CoCreateInstanceEx 、 CoGetClassObject 、 CoGetInstanceFromFile 、 CoGetInstanceFromeIStorage 。
在程序中指定服务器名字的另外一个功能是实现分布式应用系统的动态负载平衡。目前 DCOM 还 很难以实现自动负载平衡特性,但我们可以建立一个分派服务组件对象,所有的客户都创建指定机器上的分派服务组件对象,由它创建另一个真正实现应用功能的远 程对象,在把此远程对象返回给客户程序,以后客户程序不再使用分派服务组件对象,而直接调用远程对象。而分派服务组件对象可以根据当前的负载状态,从一组 服务器中选择负载最轻的服务器作为目标,创建远程对象。
8 、远程创建进程内组件:代理进程( surrogate )
为了远程运行进程内组件即 DLL 组件,要求在远程机器上有代理进程( surrogate process )。除了可以远程启动进程内组件之外,代理进程还提供了下面的特性:
l 进程内组件程序中的严重错误只影响代理进程,不会使客户进程崩溃;
l 一个代理进程可以同时为多个客户提供服务;
l 客户可以保护自己避免靠不住的组件程序代码,只访问组件程序提供的服务;
l 在代理进程中运行进程内服务可使 DLL 享有代理进程的安全性。
Windows 引进了缺省的代理进程,以及编写自定义代理进程的协议规范。缺省实现的代理进程是一个混合线程模型、伪 COM 服务程序。当多个 DLL 组件被装入到单个代理进程时,该进程按照注册表中指定的线程模型对每个 DLL 组件对象进行实例化。如果一个 DLL 组件对象支持两种线程模型,则 COM 选择自由线程模型。 COM 即可以控制 DLL 组件程序的卸载,也可以终止代理进程。
如果一个进程内组件满足下列条件,则它将被装入代理进程:
l 系统注册表中,在组件对象的 CLSID 关键字下必须要指定 AppID 值,以及对应的 AppID 关键字;
l 客户程序在创建对象实例时,必须设置 CLSTX_LOCAL_SERVER 标志;
l 组件对象的 CLSID 关键字下不指定 LocalServer32 、 LocalServer 、 LocalService 值;
l 组件对象的 CLSID 关键字包含 InProvServer32 子键;
l 在 InProcServer32 子键中指定的 DLL 文件必须存在;
l 组件对象对应的 AppID 键下指定 DllSurrogate 值。
如果组件对象的 CLSID 键下的 LocalServer 、 LocalServer32 或 LocalService 值指示了 EXE 的存在,则 EXE 程序将被优先执行, COM 不再启动代理程序。
9 、利用名字对象( moniker )连接到远程对象实例
通常 COM 对象实例是不可相互替代到,或者说不可相互交换的。它通过自己特有的状态区别于同一类的其他对象实例。
在第 8 章中介绍的 COM 命名和绑定机制对于远程对象同样适用。
10 、连接管理——远程对象生存期的控制
COM 控制对象的生存期最基本的机制是引用计数,利用 IUnknown 的 AddRef 和 Release 成员函数控制对象的生存期。 DCOM 优化了远程对象的 AddRef 和 Release 的调用。优化过程使用了 OXID ( object exporter identifier ,对象管理标识符)对象。 OXID 是一个 64 位值,通过 OXID 可以把 RPC 串绑定调用到它们的目标 IPID 。但是,在执行调用之前,调用进程必须把 OXID 转译成为底层 RPC 可以解释的一组绑定。
在每台支持 DCOM 的机器上,都有一个被称为 OXID 解析器( OXID Resolver )的服务,它负责向客户提供用于连接到 OXID 的 RPC 串绑定信息,也负责接收远程发来的“ pinging ”信息。 OXID 解析器之间通过 RPC 进行通信,它实现了 RPC 接口 IOXIDResolver (不是 COM 接口)。
11 、连接管理—— pinging 机制
如果不考虑客户进程可能会非正常终止,则利用远程引用计数控制对象生存期已经足够了。为了检测客户程序是否非正常终止, DCOM 提供了一种简单的方法“ pinging ”。在现在实现的 DCOM 版本中, pingPeriod=2 (分)且 numPingsToTimeOut=3 ,这些值不能被改变。
12 、连接管理——连接点管理
许多实际的分布式应用都需要在两个对象之间进行双向通信。由于 DCOM 是对 COM 的无缝扩展,在第 6 章中介绍的 COM 提供的连接点机制同样适用于远程对象的情形。
13 、连接管理——连接传递
用分派服务组件对象来实现分布式应用的负载平衡特性实际上用到了连接传递特性。
连接传递不等于远程对象创建的传递, DCOM 不支持位置透明方式下对象创建的传递过程,但可以利用连接传递特性,通过程序控制服务器名字的方式实现远程对象创建的传递。
14 、并发管理——线程模型
COM 本身并没有线程模型,可以认为 COM 借用了 Windows 操作系统提供的线程模型, Win32 程序设计模型把线程分成 UI 线程和辅助线程,相对应地, COM 把线程分成套间线程和自由线程。套间线程使用 CoInitialize API 函数执行 COM 库的初始化, COM 在套间线程内部创建了一个隐藏的窗口,此窗口的窗口过程函数负责把客户对套间中的组件对象的调用发送到正确的成员函数中。
15 、并发管理——消息过滤器
COM 和 DCOM 的线程模型使我们了解到了客户程序与组件对象调用过程中的线程切换,但调用可能会阻塞程序,甚至使得客户程序无法正常进行。为此, COM 提供了消息过滤机制,它既可用于客户程序,也可用于组件程序,允许它们对于入调用和出调用有所选择。
COM 把调用分为三类:第一种是同步调用,这是最常见的调用类型,客户调用组件对象,一直等到对象执行完所有功能后再返回;第二种是异步调用,客户调用组件对象,但不等到对象执行完功能就马上返回,以后对象通过出接口通知客户程序,这也就是我们在第 6 章介绍的可连接对象机制;第三种为输入同步调用,被调用对象必须在放弃控制之前返回,以便保证用户界面不受影响,也就是说,在调用执行过程中,对象不能调用任何可能会进入消息循环的函数。
16 、 DCOM 安全模型
DCOM 安全性建立在底层安全提供器基础上,有些操作系统可以支持多个安全提供器, DCOM 和 RPC 也可以同时支持多个安全提供器。所有的安全提供器有一个共同点,它们提供了一种表示安全角色(一般为用户账号)的方法、一种鉴定安全角色(一般通过口令或私有钥匙)的方法,以及管理安全角色和其鉴定数据的一套机制。
17 、 DCOM 安全模型——安全性策略
( 1 )访问安全性和激发安全性。
( 2 )对象的安全身份。
( 3 )保护数据。
( 4 )鉴定级别。
( 5 )模仿级别。
18 、 DCOM 安全模型——安全性配置
DCOM 提供了多种保护应用程序的方法,一方面, DCOM 可以强制使用安全性而不用任何对象或对象的客户程序做任何工作,对象的安全性设置可以在外部配置并且 DCOM 会自动强制使用。另一方面, DCOM 把它完整的安全性结构暴露给开发者,因而客户和对象都可以通过程序控制其安全策略。