.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 }
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的再來看一下結果:
這是編程式的示例代碼,下面給大家演示配置式的。
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

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/
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面