.Net组件程序设计之远程调用(二)

 .Net组件程序设计之远程调用(二)

激活模式

引用封送对象激活类型两种,

一种是客户端激活类型,一种是服务器端激活.

客户端激活对象   

客户端激活方式:当客户端创建一个远程对象时,客户端得到的是一个新的实例引用,新的实例可以在内存中维持状态,并且可以使用参数化构造函数来激活远程对象。

服务器激活模式single-call    

SingleCall激活方式:当客户端使用一个服务器激活方式为SingleCall的对象时,.NET为每个方法调用创建一个新对象,在方法执行完毕后,对象则被销毁,客户端虽然维持着对远程对象的引用,但是真实对象已经被销毁了。

服务器激活Singleton

Singleton激活方式:所有客户端共享一个远程对象。

下面为大家演示几段示例,就详细的清楚每一种激活方式的作用了。

服务端代码

 1     using System.Runtime.Remoting;
 2     using System.Runtime.Remoting.Messaging;
 3     namespace RemoteServer
 4     /// <summary>
 5     /// 服务端
 6     /// </summary>
 7     public class MyClass : MarshalByRefObject
 8     {
 9         public MyClass()
10         {
11             _count++;
12             string mes = AppDomain.CurrentDomain.FriendlyName;
13              Console.WriteLine(mes);
14         }
15 
16         private int _count = 0;
17 
18         public event EventHandler NumberChanged;
19 
20         public void Count()
21         {
22             _count++;
23              Console.WriteLine(AppDomain.CurrentDomain.FriendlyName + "_" + _count.ToString());
24         }
25 
26         public void OnNumberChanged(int num)
27         {
28             if (NumberChanged != null)
29             {
30                 NumberChanged(num, null);
31             }
32         }
33     }
34 
35     public class EventMehtodClass : MarshalByRefObject
36     {
37         [OneWay]
38         public void OnNumberChanged(object sender, EventArgs e)
39         {
40             if (sender != null)
41             {
42                  Console.WriteLine(sender.ToString());
43             }
44         }
45     }

2.编程式:

 1 宿主服务端(服务器端)
 2             using System.Runtime.Remoting;
 3             using System.Runtime.Remoting.Channels;
 4             using System.Runtime.Remoting.Channels.Http;
 5             using System.Runtime.Remoting.Channels.Tcp;
 6             using System.Runtime.Remoting.Channels.Ipc;
 7             using System.Runtime.Remoting.Services;
 8             using RemoteServer;
 9 
10             namespace RemoteServerHost
11 
12             #region 编程式 宿主服务端注册 信道和对象类型
13             Console.WriteLine("开始Tcp注册信道");
14             IChannel tcpChannel = new TcpChannel(8003);
15             ChannelServices.RegisterChannel(tcpChannel, false);//注册Tcp类型信道
16             Console.WriteLine("Tcp信道注册完成————————————————");
17             Console.WriteLine("开始 服务器激活类型SingleCall模式的宿主服务器端类型注册");
18             RemotingConfiguration.RegisterWellKnownServiceType(typeof(MyClass), "RWCTmyclass",WellKnownObjectMode.SingleCall);
19             Console.WriteLine("类型注册完成");
20             #endregion
21 
22             Thread.Sleep(new TimeSpan(0, 2, 0));
23             Console.WriteLine("释放Tcp信道");
24             ChannelServices.UnregisterChannel(tcpChannel);

这里所用的激活方式是 服务器SingleCall激活方式,通过RemotingConfiguration.RegisterWellKnownServiceType()方法来注册类型,第二个参数为统一资源标识符(URI),很好理解就是字面的意思,远程对象就是资源,标识资源的一个符号(名称),有了它,客户端在调用远程对象的时候才知道具体在哪。因为是服务器激活方式所以URI是在包含在注册类型的方法中的,而如果是客户端激活类型注册的话,则使用RemotingConfiguration.RegisterActivatedServiceType(typeof(MyClass));

有的朋友会问了,这样统一资源标识符不是没设置吗?是的,确实没有设置,客户端激活类型注册的时候URI是这样设置

1 RemotingConfiguration.ApplicationName = "RWCTmyclass";
 1 客户端(调用端)
 2             using System.Runtime.Remoting;
 3             using System.Runtime.Remoting.Channels;
 4             using System.Runtime.Remoting.Channels.Http;
 5             using System.Runtime.Remoting.Channels.Tcp;
 6             using System.Runtime.Remoting.Channels.Ipc;
 7             using System.Runtime.Remoting.Services;
 8             using RemoteServer;
 9 
10             namespace RemoteClient
11 
12             #region 编程式本地注册
13             Thread.Sleep(new TimeSpan(0, 0, 7));//便于调,使当前客户端线程阻塞7秒,确保宿主服务端已经运行
14             string url = "tcp://localhost:8003/RWCTmyclass";
15             Console.WriteLine("开始客户端注册类型");
16             RemotingConfiguration.RegisterWellKnownClientType(typeof(MyClass), url);
17             #endregion
18 
19 
20             //类型使用
21             MyClass myclass = new MyClass();
22             myclass.Count();
23             MyClass myclass1 = new MyClass();
24             myclass1.Count();

图 1

 因为这里使用的是服务器SingleCall类型模式激活的,所以对象状态是不保存的,就跟上面那一小节定义的一样,只有在方法调用的时候才会被创建,方法调用完毕则会被释放销毁,但是也可以在宿主服务端使用变量来记录状态。现在可以在宿主服务端(服务器端)注册类型的时候把激活模式换成Singleton的再来看一下结果:
这是编程式的示例代码,下面给大家演示配置式的。

3.配置式:

 1 宿主服务端(服务器端)
 2 using System.Runtime.Remoting;
 3 using System.Runtime.Remoting.Channels;
 4 using System.Runtime.Remoting.Channels.Http;
 5 using System.Runtime.Remoting.Channels.Tcp;
 6 using System.Runtime.Remoting.Channels.Ipc;
 7 using System.Runtime.Remoting.Services;
 8 
 9 using System.Threading;
10 
11 using RemoteServer;
12 
13 namespace RemoteServerHost
14 
15             #region 配置式宿主服务端注册 信道和对象类型
16             Console.WriteLine("开始注册Http信道");
17             RemotingConfiguration.Configure(AppDomain.CurrentDomain.FriendlyName + ".config");
18             Console.WriteLine("Http信道注册完成————————————————");
19             #endregion

这里只要使用.NET给我们提供的RemotingConfiguration类型中的Configure()方法来加载配置文件就行了,注册信道的类型,远程对象的激活方式和模式都是在配置文件中注册的,来看配置文件信息:

 1 <?xml version="1.0" encoding="utf-8" ?>
 2 <configuration>
 3   <system.runtime.remoting>
 4     <application>
 5       <channels>
 6         <channel ref="http" port="8004"/>
 7       </channels>
 8       <service>
 9         <wellknown mode="Singleton" type="RemoteServer.MyClass,RemoteServer" objectUri="RTMyClass" />
10       </service>
11     </application>
12   </system.runtime.remoting>
13 </configuration>

这里配置文件中,是准备注册http类型的信道,并且把远程对象注册为服务器激活类型(wellKnow)Singleton激活模式,宿主服务端的就这么多,接下来看客户端的.

 1 客户端
 2 using System.Runtime.Remoting;
 3 using System.Runtime.Remoting.Channels;
 4 using System.Runtime.Remoting.Channels.Http;
 5 using System.Runtime.Remoting.Channels.Tcp;
 6 using System.Runtime.Remoting.Channels.Ipc;
 7 using System.Runtime.Remoting.Services;
 8 
 9 using System.Threading;
10 
11 using RemoteServer;
12 
13 namespace RemoteClient
14 
15             #region 配置式本地注册
16             Thread.Sleep(new TimeSpan(0, 0, 7));
17             Console.WriteLine("开始客户端注册类型");
18             RemotingConfiguration.Configure(AppDomain.CurrentDomain.FriendlyName + ".config", false);
19             #endregion
20             //类型使用
21             Console.WriteLine(AppDomain.CurrentDomain.FriendlyName);
22             MyClass myclass = new MyClass();
23             myclass.Count();
24             MyClass myclass1 = new MyClass();
25             myclass1.Count();

跟宿主服务端的一样,使用Configure()方法来注册远程对象,但是本地的配置文件怎么配置呢?不着急的,一起来看:

 1 <?xml version="1.0" encoding="utf-8" ?>
 2 <configuration>
 3   <system.runtime.remoting>
 4     <application>
 5       <client>
 6         <wellknown type="RemoteServer.MyClass,RemoteServer" url="http://localhost:8004/RTMyClass"/>
 7       </client>
 8     </application>
 9   </system.runtime.remoting>
10 </configuration>

客户端 要注册的 远程对象类型 的 激活类型(客户端激活、服务器端激活) 是要跟宿主服务端的相对应。
这次换了Singleton模式

图2

4.远程回调

 1 宿主服务端:
 2         using System.Runtime.Remoting;
 3         using System.Runtime.Remoting.Channels;
 4         using System.Runtime.Remoting.Channels.Http;
 5         using System.Runtime.Remoting.Channels.Tcp;
 6         using System.Runtime.Remoting.Channels.Ipc;
 7         using System.Runtime.Remoting.Services;
 8         using System.Threading;
 9         
10         using RemoteServer;
11         namespace RemoteServerHost
12             
13 
14             #region 远程回调
15             Console.WriteLine("开始Tcp注册信道");
16             BinaryServerFormatterSinkProvider formatter = new BinaryServerFormatterSinkProvider();//二进制格式化器
17             formatter.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;//设置过滤类型为Full
18 
19             IDictionary channel = new Hashtable();
20             channel["name"] = "RWCTmyclass";
21             channel["port"] = 8003;
22 
23             IChannel tcpChannel = new TcpChannel(channel, null, formatter);
24             ChannelServices.RegisterChannel(tcpChannel, false);//注册Tcp类型信道
25             Console.WriteLine("Tcp信道注册完成————————————————");
26             Console.WriteLine("开始 服务器激活类型Singleleton模式的宿主服务器端类型注册");
27             RemotingConfiguration.RegisterWellKnownServiceType(typeof(MyClass), "RWCTmyclass", WellKnownObjectMode.Singleton);
28             Console.WriteLine("类型注册完成");
29             #endregion
30 
31 
32             Thread.Sleep(new TimeSpan(0, 2, 0));
33 
34             Console.WriteLine("释放Tcp信道");
35             ChannelServices.UnregisterChannel(tcpChannel);
 1 客户端:
 2 
 3 using System.Runtime.Remoting;
 4 using System.Runtime.Remoting.Channels;
 5 using System.Runtime.Remoting.Channels.Http;
 6 using System.Runtime.Remoting.Channels.Tcp;
 7 using System.Runtime.Remoting.Channels.Ipc;
 8 using System.Runtime.Remoting.Services;
 9 
10 using System.Threading;
11 
12 using RemoteServer;
13 
14 namespace RemoteClient
15 
16 
17             #region 远程回调
18             Thread.Sleep(new TimeSpan(0, 0, 7));
19             IChannel tcp = new TcpChannel(0);
20             ChannelServices.RegisterChannel(tcp, false);
21             string url = "tcp://localhost:8003/RWCTmyclass";
22             Console.WriteLine("开始客户端注册类型");
23             RemotingConfiguration.RegisterWellKnownClientType(typeof(MyClass), url);
24             #endregion
25 
26             Console.WriteLine(AppDomain.CurrentDomain.FriendlyName);
27             MyClass myclass = new MyClass();
28             myclass.Count();
29             EventMehtodClass methodclass = new EventMehtodClass();
30             myclass.NumberChanged += methodclass.OnNumberChanged;
31             Thread.Sleep(100);
32             myclass.OnNumberChanged(100);

图-3

在Singleton激活方式下是可以完成远程回调的,但是用Singlecall模式的话则不行,因为如果是这样的话,之前对远程对象(服务器对象)的操作都没有状态保存,上面说到过,Singlecall模式是一来一回则被释放掉了,本地客户端仅仅是保留了一个代理。可以验证一下:

修改宿主服务端的代码Singleton改为SingleCall

1 RemotingConfiguration.RegisterWellKnownServiceType(typeof(MyClass), "RWCTmyclass", WellKnownObjectMode.SingleCall);

修改客户端的代码 myclass.Count();又新加一句

1             MyClass myclass = new MyClass();
2             myclass.Count();
3             myclass.Count();
4             EventMehtodClass methodclass = new EventMehtodClass();
5             myclass.NumberChanged += methodclass.OnNumberChanged;
6             Thread.Sleep(100);
7             myclass.OnNumberChanged(100);

修改后的运行结果:
图4

为什么没有像图1中的那样发生回调这里已经不用说明了。

 

 

 

作者:金源

出处:http://www.cnblogs.com/jin-yuan/

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面

posted @ 2014-05-28 23:17  金源  阅读(1706)  评论(0编辑  收藏  举报