Inter-Object 通信
COM 旨在允许客户端以透明方式与对象进行通信,而不管这些对象在何处运行—在同一进程中、在同一台计算机上或位于另一台计算机上。 这为所有类型的对象以及对象客户端和对象服务器提供单个编程模型。
从客户端的角度来看,所有对象都通过接口指针进行访问。 指针必须是进程内。 事实上,对接口函数的任何调用始终先到达一些进程内代码片段。 如果对象正在进行中,则调用会直接到达它,无需干预系统基础结构代码。 如果对象进程外,则调用首先到达 COM 或对象提供的称为“proxy”对象(如果实现者希望)。 代理包调用参数(包括任何接口指针),并生成相应的远程过程调用(或者在自定义生成的代理的情况下的其他通信机制)到对象实现所在的其他进程或其他计算机。 用于跨进程边界传输的打包指针的过程称为 封送。
从服务器的角度来看,对对象的接口函数的所有调用都是通过指向该接口的指针进行的。 同样,指针仅在单个进程中具有上下文,调用方必须始终是一段进程内代码。 如果对象正在进行中,则调用方是客户端本身。 否则,调用方是 COM 或对象本身提供的“存根”对象。 存根从客户端进程中的“代理”接收远程过程调用(或自定义生成的代理时的其他通信机制),取消标记参数,并在服务器对象上调用相应的接口。 从客户端和服务器的角度来看,它们始终直接与一些其他进程内代码通信。
COM 提供封送处理实现,称为 标准封送。 此实现非常适用于大多数对象,并大大减少了编程要求,使封送处理过程有效透明。
但是,在一些情况下,接口与 COM 进程透明度的实现的明确分离可能会妨碍。 从客户端的角度来看,侧重于其功能的接口的设计有时会导致设计决策,这些决策与跨网络实现该接口的有效实现相冲突。 在这种情况下,需要的不是纯粹的进程透明度,而是“进程透明度,除非你需要关心”。COM 通过允许对象实现程序支持 自定义封送处理(也称为 IMarshal 封送)来提供此功能。 标准封送处理实际上是自定义封送处理实例;它是对象不需要自定义封送处理时使用的默认实现。
你可以实现自定义封送处理,以允许对象从网络使用时执行不同的作,而不是在本地访问下执行的作,并且对客户端完全透明。 借助此体系结构,可以设计客户端/对象接口而不考虑网络性能问题,然后在以后解决网络性能问题,而不会中断已建立的设计。
COM 不指定组件的结构化方式;它指定它们如何交互。 COM 将组件的内部结构留给编程语言和开发环境。 相反,编程环境没有设置使用直接应用程序外部的对象的标准。 例如,Microsoft Visual C++非常适用于在应用程序中作对象,但不支持在应用程序外部处理对象。 通常,所有其他编程语言在这方面都是相同的。 因此,为了提供网络范围的互作性,COM 通过独立于语言的接口选取编程语言离开的位置。
vtbl 结构的双重间接意味着函数指针表中的指针不需要直接指向实际对象中的实际实现。 这是流程透明度的核心。
对于进程内服务器,其中对象直接加载到客户端进程中,表中的函数指针直接指向实际实现。 在这种情况下,从客户端到接口方法的函数调用会将执行控制直接传输到该方法。 但是,这不适用于本地对象,更不用说远程对象了,因为指向内存的指针不能在进程之间共享。 不过,客户端必须能够调用接口方法,就像调用实际实现一样。 因此,客户端通过调用将控件统一传输到某些对象中的方法。
客户端始终调用一些进程内对象的接口方法。 如果实际对象是本地对象或远程对象,则调用代理对象,然后对实际对象进行远程过程调用。
那么,实际执行了哪种方法? 答案是,每当调用进程外接口时,每个接口方法都由代理对象实现。 代理对象始终是一个进程内对象,该对象代表所调用的对象执行作。 此代理对象知道实际对象在本地或远程服务器中运行。
代理对象打包某些数据包中的函数参数,并生成对本地或远程对象的 RPC 调用。 该数据包由本地或远程计算机上的服务器进程中的存根对象选取,该对象解压缩参数并调用该方法的实际实现。 当该函数返回时,存根会打包任何 out 参数和返回值,并将其发送回代理,这会将其解压缩,并将其返回到原始客户端。
因此,客户端和服务器始终相互通信,就好像所有内容都在处理中一样。 来自客户端的所有调用和对服务器的所有调用都在某个时候进行。 但是,由于 vtbl 结构允许某些代理(如 COM)截获所有函数调用和函数的所有返回,代理可以根据需要将这些调用重定向到 RPC 调用。 尽管进程内调用比进程外调用更快,但进程差异对客户端和服务器完全透明。
有关详细信息,请参阅以下主题:
相关主题