一步一步学Remoting之二:激活模式 - 中国WEB开发者网络 (http://www.webasp.net) -- 技术教程 (http://www.webasp.net/article/) --- 一步一步学Remoting之二:激活模式 (http://www.webasp.net/article/25/24488.htm) |
| -- 作者:未知 -- 发布日期: 2005-05-26 |
| 远程对象的激活模式分服务端激活和客户端激活两种,(也就是对象分服务端激活对象或者说是知名对象和客户端激活对象两种)先看看msdn怎么描述服务端激活的: 服务器激活的对象是其生存期由服务器直接控制的对象。服务器应用程序域只有在客户端在对象上进行方法调用时才创建这些对象,而不会在客户端调用 new 或 Activator.GetObject 时创建这些对象;这节省了仅为创建实例而进行的一次网络往返过程。客户端请求服务器激活的类型实例时,只在客户端应用程序域中创建一个代理。然而,这也意味着当您使用默认实现时,只允许对服务器激活的类型使用默认构造函数。若要发布其实例将使用带参数的特定构造函数创建的类型,可以使用客户端激活或者动态地发布您的特定实例。 服务器激活的对象有两种激活模式(或 WellKnownObjectMode 值):Singleton 和 SingleCall。 Singleton 类型任何时候都不会同时具有多个实例。如果存在实例,所有客户端请求都由该实例提供服务。如果不存在实例,服务器将创建一个实例,而所有后继的客户端请求都将由该实例来提供服务。由于 Singleton 类型具有关联的默认生存期,即使任何时候都不会有一个以上的可用实例,客户端也不会总接收到对可远程处理的类的同一实例的引用。 SingleCall 类型对于每个客户端请求始终只有一个实例。下一个方法调用将由另一个服务器实例提供服务,即使上一个实例尚未被系统回收。SingleCall 类型不参与生存期租约系统。 首先对于服务端激活的两种模式来做一个试验,我们把远程对象做如下的修改: using System; namespace RemoteObject { public class MyObject:MarshalByRefObject { private int i=0; public int Add(int a,int b) { return a+b; } public int Count() { return ++i; } } } 对客户端做以下修改: RemoteObject.MyObject app = (RemoteObject.MyObject)Activator.GetObject(typeof(RemoteObject.MyObject),System.Configuration.ConfigurationSettings.AppSettings["ServiceURL"]); Console.WriteLine(app.Count()); Console.ReadLine(); 第一次打开客户端的时候显示1,第二次打开的时候显示2,类推……由此验证了Singleton 类型任何时候都不会同时具有多个实例。如果存在实例,所有客户端请求都由该实例提供服务。如果不存在实例,服务器将创建一个实例,而所有后继的客户端请求都将由该实例来提供服务。 把服务器端的config修改一下: <wellknown type="RemoteObject.MyObject,RemoteObject" objectUri="RemoteObject.MyObject" mode="SingleCall" /> (这里注意大小写,大写的C) 再重新运行服务端和客户端,打开多个客户端发现始终显示1。由此验证了SingleCall 类型对于每个客户端请求始终只有一个实例。下一个方法调用将由另一个服务器实例提供服务。 下面再说一下客户端的激活模式,msdn中这么写: 客户端激活的对象是其生存期由调用应用程序域控制的对象,正如对象对于客户端是本地对象时对象的生存期由调用应用程序域控制一样。对于客户端激活,当客户端试图创建服务器对象的实例时发生一个到服务器的往返过程,而客户端代理是使用对象引用 (ObjRef) 创建的,该对象引用是从在服务器上创建远程对象返回时获取的。每当客户端创建客户端激活的类型的实例时,该实例都将只服务于该特定客户端中的特定引用,直到其租约到期并回收其内存为止。如果调用应用程序域创建两个远程类型的新实例,每个客户端引用都将只调用从其中返回引用的服务器应用程序域中的特定实例。 理解一下,可以归纳出 1、客户端激活的时间是在客户端请求的时候,而服务端激活远程对象的时间是在调用对象方法的时候 远程对象修改如下: using System; namespace RemoteObject { public class MyObject:MarshalByRefObject { private int i=0; public MyObject() { Console.WriteLine("激活"); } public int Add(int a,int b) { return a+b; } public int Count() { return ++i; } } } 服务端配置文件: <configuration> <system.runtime.remoting> <application name="RemoteServer"> <service> <activated type="RemoteObject.MyObject,RemoteObject"/> </service> <channels> <channel ref="tcp" port="9999"/> </channels> </application> </system.runtime.remoting> </configuration> 客户端程序: using System; namespace RemoteClient { class MyClient { [STAThread] static void Main(string[] args) { //RemoteObject.MyObject app = (RemoteObject.MyObject)Activator.GetObject(typeof(RemoteObject.MyObject),System.Configuration.ConfigurationSettings.AppSettings["ServiceURL"]); RemoteObject.MyObject app=(RemoteObject.MyObject)Activator.CreateInstance(typeof(RemoteObject.MyObject),null,new object[]{new System.Runtime.Remoting.Activation.UrlAttribute(System.Configuration.ConfigurationSettings.AppSettings["ServiceURL"])}); //Console.WriteLine(app.Count()); Console.ReadLine(); } } } 客户端配置文件: <configuration> <appSettings> <add key="ServiceURL" value="tcp://localhost:9999/RemoteServer"/> </appSettings> </configuration> (这里的uri按照服务端配置文件中application元素定义的RemoteServer来写) 运行程序可以看到,在客户端启动的时候服务端就输出了“激活”,我们再转回知名模式进行测试发现只有运行了方法才会在服务端输出“激活”。 2、客户端激活可以调用自定义的构造方法,而不像服务端激活只能使用默认的构造方法 把客户端代码修改如下: RemoteObject.MyObject app=(RemoteObject.MyObject)Activator.CreateInstance(typeof(RemoteObject.MyObject),new object[]{10},new object[]{new System.Runtime.Remoting.Activation.UrlAttribute(System.Configuration.ConfigurationSettings.AppSettings["ServiceURL"])}); Console.WriteLine(app.Count()); 这里看到我们在CreateInstance方法的第二个参数中提供了10作为构造方法的参数。在服务端激活模式我们不能这么做。 public MyObject(int k)![]() { this.i=k; Console.WriteLine("激活"); }毫无疑问,我们运行客户端发现输出的是11而不是1了。 using System; namespace RemoteObject { public class MyObject:MarshalByRefObject { private int i=0; public int Add(int a,int b) { return a+b; } public int Count() { return ++i; } } } 对客户端做以下修改: RemoteObject.MyObject app = (RemoteObject.MyObject)Activator.GetObject(typeof(RemoteObject.MyObject),System.Configuration.ConfigurationSettings.AppSettings["ServiceURL"]); Console.WriteLine(app.Count()); Console.ReadLine(); 第一次打开客户端的时候显示1,第二次打开的时候显示2,类推……由此验证了Singleton 类型任何时候都不会同时具有多个实例。如果存在实例,所有客户端请求都由该实例提供服务。如果不存在实例,服务器将创建一个实例,而所有后继的客户端请求都将由该实例来提供服务。 把服务器端的config修改一下: <wellknown type="RemoteObject.MyObject,RemoteObject" objectUri="RemoteObject.MyObject" mode="SingleCall" /> (这里注意大小写,大写的C) 再重新运行服务端和客户端,打开多个客户端发现始终显示1。由此验证了SingleCall 类型对于每个客户端请求始终只有一个实例。下一个方法调用将由另一个服务器实例提供服务。 下面再说一下客户端的激活模式,msdn中这么写: 客户端激活的对象是其生存期由调用应用程序域控制的对象,正如对象对于客户端是本地对象时对象的生存期由调用应用程序域控制一样。对于客户端激活,当客户端试图创建服务器对象的实例时发生一个到服务器的往返过程,而客户端代理是使用对象引用 (ObjRef) 创建的,该对象引用是从在服务器上创建远程对象返回时获取的。每当客户端创建客户端激活的类型的实例时,该实例都将只服务于该特定客户端中的特定引用,直到其租约到期并回收其内存为止。如果调用应用程序域创建两个远程类型的新实例,每个客户端引用都将只调用从其中返回引用的服务器应用程序域中的特定实例。 理解一下,可以归纳出 1、客户端激活的时间是在客户端请求的时候,而服务端激活远程对象的时间是在调用对象方法的时候 远程对象修改如下: using System; namespace RemoteObject { public class MyObject:MarshalByRefObject { private int i=0; public MyObject() { Console.WriteLine("激活"); } public int Add(int a,int b) { return a+b; } public int Count() { return ++i; } } } 服务端配置文件: <configuration> <system.runtime.remoting> <application name="RemoteServer"> <service> <activated type="RemoteObject.MyObject,RemoteObject"/> </service> <channels> <channel ref="tcp" port="9999"/> </channels> </application> </system.runtime.remoting> </configuration> 客户端程序: using System; namespace RemoteClient { class MyClient { [STAThread] static void Main(string[] args) { //RemoteObject.MyObject app = (RemoteObject.MyObject)Activator.GetObject(typeof(RemoteObject.MyObject),System.Configuration.ConfigurationSettings.AppSettings["ServiceURL"]); RemoteObject.MyObject app=(RemoteObject.MyObject)Activator.CreateInstance(typeof(RemoteObject.MyObject),null,new object[]{new System.Runtime.Remoting.Activation.UrlAttribute(System.Configuration.ConfigurationSettings.AppSettings["ServiceURL"])}); //Console.WriteLine(app.Count()); Console.ReadLine(); } } } 客户端配置文件: <configuration> <appSettings> <add key="ServiceURL" value="tcp://localhost:9999/RemoteServer"/> </appSettings> </configuration> (这里的uri按照服务端配置文件中application元素定义的RemoteServer来写) 运行程序可以看到,在客户端启动的时候服务端就输出了“激活”,我们再转回知名模式进行测试发现只有运行了方法才会在服务端输出“激活”。 2、客户端激活可以调用自定义的构造方法,而不像服务端激活只能使用默认的构造方法 把客户端代码修改如下: RemoteObject.MyObject app=(RemoteObject.MyObject)Activator.CreateInstance(typeof(RemoteObject.MyObject),new object[]{10},new object[]{new System.Runtime.Remoting.Activation.UrlAttribute(System.Configuration.ConfigurationSettings.AppSettings["ServiceURL"])}); Console.WriteLine(app.Count()); 这里看到我们在CreateInstance方法的第二个参数中提供了10作为构造方法的参数。在服务端激活模式我们不能这么做。 public MyObject(int k)![]() { this.i=k; Console.WriteLine("激活"); }毫无疑问,我们运行客户端发现输出的是11而不是1了。 |
| webasp.net |