简介
Microsoft® .NET Remoting 提供了一种允许对象通过应用程序域与另一对象进行交互的框架。这种框架提供了多种服务,包括激活和生存期支持,以及负责与远程应用程序进行消息传输的通讯通道。格式化程序用于在消息通过通道传输之前,对其进行编码和解码。应用程序可以在注重性能的场合使用二进制编码,在需要与其他远程处理框架进行交互的场合使用 XML 编码。在从一个应用程序域向另一个应用程序域传输消息时,所有的 XML 编码都使用 SOAP 协议。出于安全性方面的考虑,远程处理提供了大量挂钩,使得在消息流通过通道进行传输之前,安全接收器能够访问消息和序列化流。
通常,如果没有底层框架的支持,管理远程对象的生存期会非常麻烦。.NET Remoting 提供了许多可供选择的生存期模型,这些模型分为两个类别:客户端激活对象和服务器激活对象
客户端激活对象受基于租用的生存期管理器的控制,这种管理器确保了租用期满时对象可被回收。而对于服务器激活对象,开发人员则可以选择“单一调用”模式或“单一元素”模式。
远程对象
任何远程处理框架的主要目的之一就是要提供必要的基础结构,以便隐藏远程对象调用方法和返回结果的复杂性。任何位于调用方应用程序域之外的对象,即使在同一台计算机上执行,也会被认为是远程对象。在应用程序域内部,原始数据类型按数值传递,而所有的对象按引用传递。因为本地对象引用仅在创建对象的应用程序域内有效,所以它们不能以这种方式传递到远程方法调用或从远程方法调用返回。所有必须跨越应用程序域的本地对象都必须按数值来传递,并且应该用 [serializable] 自定义属性作标记,否则它们必须实现 ISerializable 接口。对象作为参数传递时,框架将该对象序列化并传输到目标应用程序域,对象将在该目标应用程序域中被重新构造。无法序列化的本地对象将不能传递到其他应用程序域中,因而也不能远程处理。
通过从 MarshalByRefObject 导出对象,您可以使任一对象变为远程对象。当某个客户端激活一个远程对象时,它将接收到该远程对象的代理。对该代理的所有操作都被适当地重新定向,使远程处理基础结构能够正确截取和转发调用。尽管这种重新定向对性能有一些影响,但 JIT 编译器和执行引擎 (EE) 已经优化,可以在代理和远程对象驻留在同一个应用程序域中时,防止不必要的性能损失。如果代理和远程对象不在同一个应用程序域中,则堆栈中的所有方法调用参数会被转换为消息并被传输到远程应用程序域,这些消息将在该远程应用程序域中被转换为原来的堆栈帧,同时该方法调用也会被调用。从方法调用中返回结果时也使用同一过程。
代理对象
代理对象是在客户端激活远程对象时创建的。作为远程对象的代表,代理对象确保对代理进行的所有调用都能够转发到正确的远程对象实例。为了准确理解代理对象的工作方式,我们需要更深入地研究它们。当某个客户端激活一个远程对象时,框架将创建 TransparentProxy 类的一个本地实例(该类中包含所有类的列表与远程对象的接口方法)。因为 TransparentProxy 类在创建时用 CLR 注册,所以代理上的所有方法调用都被运行时截取。这时系统将检查调用,以确定其是否为远程对象的有效调用,以及远程对象的实例是否与代理位于同一应用程序域中。如果对象在同一个应用程序域中,则简单方法调用将被路由到实际对象;如果对象位于不同的应用程序域中,将通过调用堆栈中的调用参数的 Invoke 方法将其打包到 IMessage 对象并转发到 RealProxy 类中。此类(或其内部实现)负责向远程对象转发消息。TransparentProxy 类和 RealProxy 类都是在远程对象被激活后在后台创建的,但只有 TransparentProxy 返回到客户端。
要更好地理解这些代理对象,我们需要简要介绍一下 ObjRef。激活一节中有关于 ObjRef 的详细说明。以下方案简要说明了 ObjRef 与这两个代理类的关联方式。但请注意,这只是关于该进程的一个极其概括的说明;根据对象是客户端激活对象还是服务器激活对象,以及它们是单一元素对象还是单一调用对象,该进程会有所不同。
远程对象注册在远程计算机的应用程序域中。远程对象被封送以生成 ObjRef。ObjRef 包含了从网络上的任意位置定位和访问远程对象所需的所有信息,包括:类的增强名称、类的层次结构(其父类)、类实现的所有接口的名称、对象 URI 和所有已注册的可用通道的详细信息。在接收到对某个远程对象的请求时,远程处理框架使用对象 URI 来检索为该对象创建的 ObjRef 实例。
客户端通过调用 new 或某个 Activator 函数(例如 CreateInstance)来激活远程对象。对于服务器激活对象,远程对象的 TransparentProxy 将在客户端应用程序域中生成并返回到客户端,这时不执行任何远程调用。只有在客户端调用远程对象的某个方法时,该远程对象才会被激活。此方案明显不适合客户端激活对象,因为客户端希望框架只在得到请求时才激活对象。当客户端调用某个激活方法时,客户端上会创建一个激活代理,并且将使用 URL 和对象 URI 作为终结点在服务器的远程激活器上初始化一个远程调用。远程激活器激活该对象,然后 ObjRef 流向客户端,并被取消封送以生成一个返回给客户端的 TransparentProxy。
取消封送的过程中会分析 ObjRef 以提取远程对象的方法信息,同时还会创建 TransparentProxy 和 RealProxy 对象。在用 CLR 注册 TransparentProxy 之前,分析后的 ObjRef 内容会被添加到 TransparentProxy 的内部表中。
TransparentProxy 是一种无法替代和扩展的内部类,而 RealProxy 和 ObjRef 类则属于公共类,可以在必要时进行扩展和自定义。因为 RealProxy 类能够处理远程对象的所有函数调用,所以它是执行负载平衡等操作的理想方法。调用 Invoke 时,从 RealProxy 导出的类可以获得网络中服务器的负载信息,并将该调用路由到适当的服务器。简单地为所需的 ObjectURI 从通道请求一个 MessageSink,并调用 SyncProcessMessage 或 AsyncProcessMessage 以将该调用转发至所需的远程对象。当调用返回时,通过调用 RemotingServices 类的 PropagateMessageToProxy 将返回参数推回到堆栈中。
下面的代码片断显示了如何使用导出的 RealProxy 类。
MyRealProxy proxy = new MyRealProxy(typeof(Foo));
Foo obj = (Foo)proxy.GetTransparentProxy();
int result = obj.CallSomeMethod();
上例中获取的 TransparentProxy 可以被转发到另一个应用程序域中。当第二个客户端试图调用代理上的某个方法时,远程处理框架会尝试创建 MyRealProxy 类的实例,并且如果程序集可用,所有的调用都会路由至此实例。如果程序集不可用,调用会路由至默认的远程 RealProxy。
通过为默认的 ObjRef 属性 TypeInfo、EnvoyInfo 和 ChannelInfo 提供替代,可以很容易地自定义 ObjRef。下列代码显示了如何进行自定义:
public class ObjRef { |
通道
通道用于在远程对象之间传输消息。当客户端调用某个远程对象上的方法时,与该调用相关的参数以及其他详细信息会通过通道传输到远程对象。调用的任何结果都会以同样的方式返回给客户端。客户端可以选择“服务器”中注册的任一通道,以实现与远程对象之间的通讯,因此开发人员可以自由选择最适合需要的通道。当然,也可以自定义任何现有的通道或创建使用其他通讯协议的新通道。通道选择遵循以下规则:
在能够调用远程对象之前,远程处理框架必须至少注册一个通道。通道注册必须在对象注册之前进行。
通道按应用程序域注册。一个进程中可以有多个应用程序域。当进程结束时,该进程注册的所有通道将被自动清除。
多次注册侦听同一端口的通道是非法的。即使通道按应用程序域注册,同一计算机上的不同应用程序域也不能注册侦听同一端口的通道。
客户端可以使用任何已注册的通道与远程对象通讯。当客户端试图连接至某个远程对象时,远程处理框架会确保该对象连接至正确的通道。客户端负责在尝试与远程对象通讯之前调用 ChannelService 类的 RegisterChannel。
所有的通道都由 IChannel 导出,并根据通道的用途实现 IChannelReceiver 或 IchannelSender。大多数通道既实现了接收器接口,又实现了发送器接口,使它们可以在两个方向上通讯。当客户端调用代理上的某个方法时,远程处理框架会截取该调用并将其转为要发送到 RealProxy 类(或一个实现 RealProxy 类的实例)的消息。RealProxy 将消息转发到消息接收器以进行处理。消息接收器负责与远程对象注册的通道之间建立连接,并通过通道(在不同的应用程序域)将消息从调度位置传输到远程对象本身。激活了一个远程对象后,客户端会通过调用选定通道上的 CreateMessageSink 来选择通道,并从其上检索能够与远程对象通讯的消息接收器。
远程处理框架的一个容易混淆的方面是远程对象和通道之间的关系。例如,如果 SingleCall 远程对象只在被调用时才激活,那么该对象如何侦听要连接的客户端?
部分答案在于这样一个事实:远程对象并不拥有自己的通道,而是共享通道。作为远程对象宿主的服务器应用程序必须注册要通过远程处理框架公开的对象以及所需的通道。注册后的通道会自动开始在指定的端口侦听客户请求。注册远程对象后,会为该对象创建一个 ObjRef 并将其存储在表中。当通道上传来一个请求时,远程处理框架会检查该消息以确定目标对象,同时检查对象引用表以定位表中的引用。如果找到了对象引用,将从表中检索框架目标对象或在必要时将其激活,然后框架将调用转发至该对象。对于同步调用,在消息调用期间会一直维持来自客户端的连接。因为每个客户端连接都在自己的线程上处理,所以一个通道可以同时服务于多个客户端。
生成商务应用时,安全性是一个重要问题。要满足商务要求,开发人员必须能给远程方法调用添加诸如授权或加密等安全特性。为了实现这一目标,开发人员可以自定义通道,使其能够对与远程对象之间的实际消息传输机制进行控制。在传输到远程应用程序之前,所有的消息都必须流过 SecuritySink、TransportSink 和 FormatterSink,且这些消息传递到远程应用程序后会以相反次序流过同样的接收器。
HTTP 通道
HTTP 通道使用 SOAP 协议与远程对象传输消息。所有的消息流过 SOAP 格式化程序时都被转换为 XML 格式且被序列化,所需的 SOAP 头也会被添加到该流中。您也可以指定能够生成二进制数据流的二进制格式化程序。然后,数据流会使用 HTTP 协议传输到目标 URI。
TCP 通道
TCP 通道使用二进制格式化程序将所有的消息序列化为二进制流,并使用 TCP 协议将其传输到目标 URI。
激活
远程处理框架支持远程对象的服务器激活和客户端激活。不需要远程对象在方法调用之间维护任何状态时,一般使用服务器激活。服务器激活也适用于多个客户端调用方法位于同一对象实例上、且对象在函数调用之间维持状态的情况。另一方面,客户端激活对象从客户端实例化,并且客户端通过使用基于租用的专用系统来管理远程对象的生存期。
在可以接受客户端的访问之前,所有的远程对象都必须用远程处理框架注册。对象注册一般由宿主应用程序来完成。宿主应用程序将启动,使用 ChannelServices 注册一个或多个通道,使用 RemotingServices 注册一个或多个远程对象,然后等待被终止。请注意,已注册的通道和对象只有在用来注册它们的进程活动时才可以使用。如果退出了该进程,则会自动从远程处理服务中删除它注册的所有通道和对象。在框架中注册远程对象时,需要以下四项信息:
包含类的程序集名称。
远程对象的类型名称。
客户端定位对象时将使用的对象 URI。
服务器激活所需的对象模式。该模式可以是 SingleCall,也可以是 Singleton。
远程对象可以通过下列两种方式注册:调用 RegisterWellKnownType,将上述信息作为参数传递;或将上述信息存储在配置文件中,然后调用 ConfigureRemoting 并将该配置文件的名称作为参数传递。以上两种方法执行的功能相同,因此您可以使用它们中的任意一种来注册远程对象。当然,后一种方法更方便些,因为无需重新编译宿主应用程序即可改变配置文件的内容。以下代码片断显示了如何将 HelloService 类注册为 SingleCall 远程对象。
RemotingServices.RegisterWellKnownType( |
ChannelServices.RegisterChannel(new TCPChannel); |
GetObject 或 new 可用于服务器激活对象。请注意,使用这两个调用时不会实例化对象,实际上不会生成任何网络调用。框架从元数据获得了创建代理所需的足够信息,但并未连接到远程对象上。只有在客户端调用代理上的某个方法时才会建立网络连接。当调用抵达服务器时,框架将从消息中提取 URI,检查远程处理框架表以便定位与 URI 匹配的对象引用,然后在必要时将对象实例化,并将方法调用转发至对象。如果将对象注册为 SingleCall,则完成方法调用后该对象会取消。每次调用一个方法时,都会创建一个新的实例。GetObject 和 new 之间的唯一差别在于,前者允许指定 URL 作为参数,而后者从配置中获得 URL。
CreateInstance 或 new 可用于客户端激活对象。两者都允许使用带参数的构造函数来实例化对象。客户端激活对象的生存期由远程处理框架提供的租用服务控制。对象租用的内容在下一节中说明。
| 共2页: 1 [2] 下一页 | ||
|
|
|||
| · 我是黑客我怕谁——讲.. · ARP攻击防范与解决方案 · Solaris 10 配置管理 · Solaris基础知识入门 · RIP路由协议专栏 · MPLS路由协议专栏 · OSPF路由协议专栏 · 思科路由器产品 |
· 华为路由器产品 · 路由器模拟器 · AIX操作系统管理应用(.. · 思科路由器配置 · 路由器组网解决方案 · 路由器密码恢复 · 无线路由器故障处理 · 路由故障处理手册 |
||
|
|||
| · Java基础教程 · VPN技术 · SQL Server 2005全解 · ARP攻击防范与解决方案 · SOA 面向服务架构 · SQL Server 2005全解 · Java编程开发手册 · 三层交换技术专题 |
· SQL Server入门到精通 · Windows Server 2003企.. · Windows远程桌面应用 · C#技术开发指南 · VPN技术 · Solaris 10 配置管理 · C#技术开发指南 · Windows操作系统安装 |
||
|
|||
| · ARP攻击防范与解决方案 · VPN技术 · SQL Server 2005全解 · Java基础教程 · SQL Server入门到精通 · SQL Server 2005全解 · SOA 面向服务架构 · Java编程开发手册 |
· C#技术开发指南 · 三层交换技术专题 · C#技术开发指南 · Windows远程桌面应用 · Windows Server 2003企.. · 邮件服务器专题 · wimax技术与趋势 · Windows操作系统安装 |
||
| ·DB2 Viper快速入门 ·DB2 9数据库的镜像分割与.. |
·将XML应用程序从DB2 8.x.. ·DB2 9中的pureXML:如何.. |
| ·服务器中的“傻瓜机”在.. ·盖茨也喜欢登录Youtube看.. |
· · |
| ·网名接龙--之大话黄琨 ^o^ ·ARP欺骗引发的“冤案”—.. |
·ARP欺骗的原理、步骤和危.. ·利用负载均衡技术针对Web.. |
| ·VMware Workstation 6.01.. ·Windows Server 2008 RC0.. |
·ISA Server 2006的全自动.. ·ISA Server、虚拟机、托.. |
| · NGN:下一代网络 · 网络访问中断大排查 · FTTx光纤接入 |
· IT基础教程 · 平凡黑客讲述精彩人生(.. · 平凡黑客讲述精彩人生(.. |
| · C++是垃圾语言?! · 2007年IT界七大抄袭事件 · Java实用开发全集 |
· 解析Ajax开发框架 走进A.. · 基于Google Maps与Ajax.. · 基于Google Maps与Ajax.. |
| · 热门 IT 培训认证官方资.. · Ubuntu 中文开源频道 · Solaris基础知识入门 |
· AMD三核心处理器解析 痛.. · 服务器基础知识入门 · Rambus第二?看全缓冲内.. |
| · 甲骨文Oracle 11g正式发.. · Oracle数据库开发之PL/S.. · Oracle数据库开发基础教.. |
· 存储2006,一个并购的大.. · IDC宣布浪潮蝉联存储市.. · 双机热备技术 |