当一个remoteing实例被建立了以后,他什么时候开始为我们工作呢,甚么时候又从内存中消失的呢,我们能够很明确的知道这些吗,我们可以随心所欲的控制他吗?这些问题就是今天所要说的激活。激活分为服务器激活(知名wellknonw)和客户端激活。服务器激活分为单调用对象(SingleCall)和单元素对象(Singleton)。 还是先看一个单元素激活的例子。 根据上次的例子我们只要做少许修改就可以了。 先在dll对象里面加一个计数器,通过这个计算器我们可以了解到实例的变化。using System;
namespace RemoteObject { public class MyObject:MarshalByRefObject { private int i=0;
public int Add(int a,int b) { return a+b; } public string str() { return "i am come from server:"; } public int Count() { return ++i; }
} } 然后客户端加一个调用这个计数器的过程。using System;
namespace RemoteClient{ class MyClient { [STAThread] static void Main(string[] args) { RemoteObject.MyObject remoteclient = (RemoteObject.MyObject)
Activator.GetObject(typeof
(RemoteObject.MyObject),System.Configuration.ConfigurationSettings.AppSettings
["ServiceURL"]); Console.WriteLine(remoteclient.str()+remoteclient.Add(1,2)); Console.WriteLine(remoteclient.Count()); Console.ReadLine(); } }} 其他服务器端没有变化。 我们运行1次服务器端的程序,不要关掉,然后我们开一个客户端,上面显示的是1,再开一个客户端,上面显示的是2,再开,又显示是3,依此类推,数字越来越多,只要服务器不关,这个数字就在不断增加。在做一个单调用的例子。 这次就在以上的代码的基础上。把服务器的配置文件做少许修改。<wellknown type="RemoteObject.MyObject,RemoteObject" objectUri="RemoteObject.MyObject" mode="SingleCall" /> 然后做以上相同的试验:我们运行1次服务器端的程序,不要关掉,然后我们开一个客户端,上面显示的是1,再开一个客户端,上面显示的是1,再开,又显示是1,依此类推,只要服务器不关,这个数字就永远显示1。很多朋友就会在这里混淆了,因为从试验看起来似乎单元素对象在不断增加,而单调用对象才是永远不变。其实不然。 先看看MSDN里面怎么解释:“Singleton 对象是这样的对象:无论该对象有多少个客户端,总是只有一个实例,且该对象具有默认的生存期。(客户端可以使用生存期租约系统来参与 Singleton 实例的生存期。有关详细信息,请参见生存期租约。)当您将对象配置为 SingleCall 对象时,系统将为每个客户端方法调用创建一个新对象。由于客户端将在每次调用时获取对新实例的引用,因此 SingleCall 类型不会参与生存期租约系统。” 其实以前见过一本书,对于这两种做了一个很清晰的解释,这样说:“SingleCall是单调用对象,每次调用都被实例化(会有多个实例),并且最后会被无用单元收集器销毁。Singleton 是单元素对象,只是在第一次调用的时候实例化,然后留在那里直到最后一个客户把他释放”。 清楚了服务器的激活,再来看看客户端激活。 为了知道客户端激活和服务器激活的不同点,我们配合两者做一个试验。 远程对象修改如下: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> 运行程序可以看到,在客户端启动的时候服务端就输出了“激活”,我们再转回知名模式进行测试发现只有运行了方法才会在服务端输出“激活”。
小结: 客户端激活类似于单调用对象,每次激活都会有一个新的实例产生,客户端和服务器端激活的区别在于:服务器端激活要在第一次调用了客户端方法的时候,被激活,同样也就是dll在服务器和容器(服务器程序)里面被注册和申请空间,而客户端激活的话,在客户端发出请求的时候就被实例化(注册和申请空间)。(感谢lovecherry的blog,我的文章里面加入了一些自己的理解和思考,如果大家想看到纯净版的remoting请看http://www.cnblogs.com/lovecherry。不敢掠人之美。)