现在的位置: 首页 > 综合 > 正文

。net remoting 使用详解

2014年02月14日 ⁄ 综合 ⁄ 共 6229字 ⁄ 字号 评论关闭

    隔了这么多天,终于炮制出了自己关于.NET Remoting技术在项目中的应用总结。

2Remoting技术的应用

       根据需求,我们的系统必须以C/S方式构建,而且是三层架构,这样一来,就出现了服务器端和客户端通信的问题。      

 

       为了解决双方的通信问题,还要考虑效率、性能等方面,经过分析、试验,我们根据效率、移植、开发难易等几个因素,舍弃了一开始提出的WebService、消息队列机制,以及有人建议的基于流I/O自己解析数据的通信方式,在分析了目前主流的RPC方式(DCOMCORBA.NET Remoting)及我们的开发平台后,最终选择了微软新推出的.NET Remoting机制。我们的原因如下:

       1.NET Remoting是目前分布式对象实现RPC的一种主要方式。

       2.NET Remtoing在性能上可以达到DCOM,或者与之相差不多。

       3.NET Remoting建立在.NET定义的公共数据类型CTS及运行环境CLR之上,和.NET框架有着很好的互操作性,因此功能强大切易于使用。

       4、扩展性和安全性方面都比较好。

 

       从试验结果来看,该机制可以实现C/S模式下的双方通信,而且在性能上具有很好的保障。根据我们开发完毕的系统性能来看,Remoting机制很好的实现了我们赋予它的任务,或者说,我们采用Remoting机制达到了我们预期的目标。

 

       下面,对我们采用Remoting机制进行开发这一从无到有过程中的一些资料、感悟进行整理。

 

2.1 基本概念

       .NET Remoting是微软随.NET推出的一种分布式应用解决方案,被誉为管理应用程序域之间的 RPC 的首选技,它允许不同应用程序域之间进行通信(这里的通信可以是在同一个进程中进行、一个系统的不同进程间进行、不同系统的进程间进行)。

 

       更具体的说,Microsoft .NET Remoting 提供了一种允许对象通过应用程序域与另一对象进行交互的框架。也就是说,使用.NET Remoting,一个程序域可以访问另外一个程序域中的对象,就好像这个对象位于自身内部,只不过,对这个远程对象的调用,其代码是在远程应用程序域中进行的,例如在本地应用程序域中调用远程对象上一个会弹出对话框的方法,那么,这个对话框,则会在远程应用程序域中弹出。

 

.NET Remoting框架提供了多种服务,包括激活和生存期支持,以及负责与远程应用程序进行消息传输的通讯通道。格式化程序用于在消息通过通道传输之前,对其进行编码和解码。应用程序可以在注重性能的场合使用二进制编码,在需要与其他远程处理框架进行交互的场合使用 XML 编码。在从一个应用程序域向另一个应用程序域传输消息时,所有的 XML 编码都使用 SOAP 协议。出于安全性方面的考虑,远程处理提供了大量挂钩,使得在消息流通过通道进行传输之前,安全接收器能够访问消息和序列化流。

      

.NET Remoting协同工作能力

 

       下图是.NET Remoting的体系结构图

 

.NET Remoting通信体系结构

 

一般来说,.NET Remoting包括如下几点主要元素:

Ø         远程对象:运行在Remoting服务器上的对象。客户端通过代理对象来间接调用该对象的服务,如上图的“通信体系结构”所示。在.NET Remoting体系中,要想成为远程对象提供服务,该对象的类必须是MarshByRefObject的派生对象。另外,要说明的是,需要在网络上传递的对象,例如“参数”,则必须是可序列化的。

Ø         信道:信道是服务器和客户机进行通信用的(这里的服务器和客户机并不一定都是计算机,也可能是进程)。在.NET Remoting中,提供了三种信道类型:TCPHTTPIPC,另外,也可以定制不同的信道以适应不同的通信协议(至于如何定制,我尚未涉及到,因此,不好说)。

Ø         消息:客户机和服务器通过消息进行信息交换,消息在信道中传递。这里的消息包括,远程对象的信息,调用方法名称,参数,返回值等。

Ø         格式标识符:该标识符标明了消息是按照什么样的格式被发送到信道上的,目前.NET 2.0提供了两种格式标识符:SOAP格式和二进制格式。SOAP格式标识符符合SOAP标准,比较通用,可以和非.NET 框架的Web服务通信。二进制格式标识符,则在速度、效率上面更生一筹,但通用性较SOAP差。另外,Remoting还支持自定义的格式标识符。(顺便说一下:TCP信道,默认使用二进制格式传输,因为这个效率更高;Http信道则默认使用SOAP格式;不过在系统中,哪种信道具体使用哪种格式,则是可以根据需要设置的。)。

Ø         格式标识符提供程序:它用于把格式标识符和信道联系起来。在创建信道时,可以指定所要使用的标识符提供程序,一旦指定了提供程序,那么消息被发送到信道上的格式也就确定了下来。

 

为序列化消息, .NET Remoting 提供了两类格式程序接收器: BinaryFormatterSoapFormatter。选择的类型很大程度上取决于连接分布式对象的网络环境的类型。由于. NET  Remoting体系结构的可插入特性,可以创建自己的格式程序接收器,并插入到.NET Remoting基础设施中。这种灵活性使基础设施能够支持可能的各种线路格式。

 

对于可以发送并接收二进制数据(例如TCP/IP)的网络传输协议,可以使用System.Runtime.Serialization.Formatters.Binary名字空间中定义的BinaryFormatter类型。顾名思义,BinaryFormatter将消息对象序列化为一个二进制格式的流。这是消息对象在线缆间进行传输的最有效而简洁的表示方式。一些网络传输系统不允许发送和接收二进制数据。这类传输迫使应用程序在发送之前将所有的二进制数据转换成ASCII文本表示形式。在这种情况下(或者要得到最佳协作能力的时候),.NET RemotingSystem.Runtime.Serialization.Formatters.Soap名字空间中提供SoapFormatter类型。SoapFormatter使用消息的SOAP表示形式将消息序列化为流。

 

下面为创建信道的一个示例过程。

 

//标识符提供程序

BinaryServerFormatterSinkProvider serverProvider = new BinaryServerFormatterSinkProvider();

serverProvider.TypeFilterLevel = TypeFilterLevel.Full;

 

//信道名称及端口

IDictionary dict = new Hashtable();

dict["name"] = "MacSystem.Server.Channel";

dict["port"] = 8087;

 

//注册TCP通信信道

TcpServerChannel serverChannel = new TcpServerChannel(dict, serverProvider);              

ChannelServices.RegisterChannel(serverChannel, false);

 

 

Ø         代理对象:前面也说过,客户端不能直接调用远程对象,客户机只能通过代理对象来操作远程对象。代理对象,又分为透明代理和真实代理。在客户机看来,代理对象和远程对象是一样的。客户机调用透明代理对象上的方法,透明代理再调用真实代理上的Invoke方法,Invoke方法再使用消息接受器把消息传递到信道上。

下图是客户机的方法调用导致消息在信道间传递的一个体系结构图:

 

消息在信道上的传递过程

Ø         消息接受器:如上图所示,消息接受器在服务器端和客户端都有,接受真实代理的调用,把序列化的消息发布到信道上。

Ø         激活器:这涉及到对象生命期管理,客户机使用激活器在服务器上创建远程对象,或者说是申请一个远程对象的引用。

Ø         RemotingConfiguration类:该类用于配置远程服务器和客户机的一个实用类,它可以用于读取配置文件或者动态地配置远程对象。说明一点的是:RemotingConfiguration类中的大部分属性、方法都是静态的,这就意味着很多属性,如应用程序名称,只能通过当前属性或配置文件设置一次。如果应用程序运行在宿主环境中,例如 Internet 信息服务 (IIS),则可能已经设置了该值(通常将其设置为虚拟目录)。如果未设置应用程序名称,则当前属性将返回空引用

Ø         ChannelServices类:该类用于注册信道,并把消息分派到信道上。

 

//服务器端:演示如何使用 ApplicationName 属性指示远程处理应用程序的名称

ChannelServices.RegisterChannel(new TcpChannel(8082));

 

RemotingConfiguration.ApplicationName = "HelloServiceApplication";

RemotingConfiguration.RegisterWellKnownServiceType( typeof(HelloService),

         "MyUri",   WellKnownObjectMode.SingleCall  );

 

//客户端:演示如何从指定的应用程序访问远程对象

ChannelServices.RegisterChannel(new TcpChannel());

RemotingConfiguration.RegisterWellKnownClientType(typeof(HelloService), "tcp://localhost:8082/HelloServiceApplication/MyUri" );

 

HelloService service = new HelloService();

 

 

2.2应用步骤

2.2.1、服务器端

       第一步:确定使用的信道。

       前面已经说过,.NET Remoting提供了三种预定义的信道:TCPHTTPIPC,他们各有自己的特点,根据自己需要进行选择。对于每个信道,都有一些可以配置的信息,如:

Ø         信道名称:若不指定,则使用默认名称,每种信道,都有默认的信道名称;不过为了区分计,开发者最好给自己创建的信道命名。

Ø         信道使用的格式化提供程序:如果不指定,则使用默认形式。

Ø         信道优先级:优先级越高,则被选择进行连接的机会则越大。

Ø         信道的端口:服务器端信道,则必须具备一个所有客户都知道的端口即固定端口,客户端则可以由系统自动分配端口。

Ø         ……其它属性参见MSDN

 

下面是一些创建信道的示例代码:

 

// 1. 使用默认构造函数创建一个TCP侦听信道

TcpServerChannel serverChannel = new TcpServerChannel(9090);

ChannelServices.RegisterChannel(serverChannel);

 

// 2. 使用带信道配置属性的形式创建TCP侦听信道

IDictionary dict = new Hashtable();

dict["port"] = 9090;

dict["authenticationMode"] = "IdentifyCallers";

 

TcpServerChannel serverChannel = new TcpServerChannel(dict, null);

ChannelServices.RegisterChannel(serverChannel);           

 

// 3. 指定信道名称、端口及格式标识符提供程序的形式创建信道

BinaryServerFormatterSinkProvider serverProvider = new BinaryServerFormatterSinkProvider();

serverProvider.TypeFilterLevel = TypeFilterLevel.Full;

TcpServerChannel channel = new TcpServerChannel( "Server Channel",

         9090, serverProvider);

ChannelServices.RegisterChannel(serverChannel,false);

 

 

       第二步:注册信道。

       注册信道就是把已经创建的信道,使用ChannelServices类的RegisterChannel方法来“向信道服务注册信道”

       示例代码如上所示。

 

       第三步:注册远程对象。

       服务器端打算发布一个可以被客户端调用的远程对象,那它必须以某种方式“告诉”系统:我这里有一个这样的服务可供你使用。这里的“告诉”的过程,就是注册远程对象。

 

       .NET Remoting中,注册远程对象,使用RemotingConfiguration类提供的静态方法RegisterWellKnownServiceTypeRegisterActivatedServiceType来进行注册。至于选择哪种注册方式,则根据远程对象的激活方式而定。关于这两个方法,做如下说明:

 

RegisterWellKnownServiceType

功能:将服务端上的对象 Type 注册为已知类型(“单个调用”(singlecall) singleton)。

激活方式:服务器端激活

服务器端激活模式又有两种Singleton SingleCall,说明如下

Singleton

在这种模式中,任何时候内存中都只有一个实例,所有客户端都接受该实例提供的服务,如果不存在实例,服务器将创建一个实例。但要注意,这些类型都有与之相关的默认生存期。这意味着对于可进行远程处理的类,客户端不一定总是接收对这个类的同一实例的引用。后一种情况对状态管理很有意义,也是这种 Remoting 模式与传统的 Singleton 模式(要求对象标识相同)的不同之处。如果您的设计需要使用传统的 Singleton 状态管理模式,有两种方法可以解决此问题。一种方法是忽略默认的对象租用行为,以便在主机应用程序域运行时始终将对象保存在内存中。以下代码片段说明了如何做到这一点:

public class MyClass : MarshalByRefObject

{ 

public override Object InitializeLifetimeService()  { return null;  }

}

这种机制将对象锁定到内存中,防止对象被回收,但只能在主机应用程序运行期间做到这样。对于 IIS 集成,如果集成 Remoting 会话的 IIS IIS 进程被回收(很多原因可以导致这种现象),那么对象将被破坏。

要完全依赖 Remoting 的线程安全的 Singleton

抱歉!评论已关闭.