WCF分布式开发必备知识(2):.Net Remoting
生活随笔
收集整理的這篇文章主要介紹了
WCF分布式开发必备知识(2):.Net Remoting
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
上一節(jié)我們學(xué)習(xí)了網(wǎng)絡(luò)分布式編程中的MSMQ消息隊(duì)列技術(shù).本節(jié)我們將學(xué)習(xí)分布式編程的另外一個(gè)重要的技術(shù).Net Remoting,文章的結(jié)構(gòu)還是先討論基本概念,再來(lái)探討具體的技術(shù)實(shí)現(xiàn),希望能和大家一起交流學(xué)習(xí). .Net Remoting技術(shù),我們可以將其看作是一種分布式處理方式。作為應(yīng)用程序之間通信的一種機(jī)制,.Net Remoting與MSMQ消息隊(duì)列不同,它不支持離線脫機(jī)消息,另外只適合.Net平臺(tái)間程序的通信.從微軟的產(chǎn)品角度來(lái)看,可以說(shuō)Remoting就是分布式組件DCOM的一種升級(jí),它改善了很多功能,并極好的融合到.Net平臺(tái)下。.NET Remoting 提供了一種允許對(duì)象通過應(yīng)用程序域與另一對(duì)象進(jìn)行交互的框架。這也正是我們使用Remoting的原因。為什么呢?在Windows操作系統(tǒng)中,是將應(yīng)用程序分離為單獨(dú)的進(jìn)程。這個(gè)進(jìn)程形成了應(yīng)用程序代碼和數(shù)據(jù)周圍的一道邊界。如果不采用進(jìn)程間通信IPC(Internet Process Connection)機(jī)制,則在一個(gè)進(jìn)程中執(zhí)行的代碼就不能訪問另一進(jìn)程。這是一種操作系統(tǒng)對(duì)應(yīng)用程序的保護(hù)機(jī)制。然而在某些情況下,我們需要跨過應(yīng)用程序域,與另外的應(yīng)用程序域進(jìn)行通信,即穿越邊界(參考MSDN)。 .Net Remoting的通信架構(gòu)如下圖. 我們可以通過上圖簡(jiǎn)單理解一下.Net Remoting的通信框架,而現(xiàn)在來(lái)介紹一下其中涉及到的幾個(gè)比較重要的概念: 1.通道(channel), 在.Net Remoting中是通過通道(channel)來(lái)實(shí)現(xiàn)兩個(gè)應(yīng)用程序域之間對(duì)象的通信的。首先,客戶端通過Remoting,訪問通道以獲得服務(wù)端對(duì)象,再通過代理解析為客戶端對(duì)象。這就提供一種可能性,即以服務(wù)的方式來(lái)發(fā)布服務(wù)器對(duì)象。遠(yuǎn)程對(duì)象代碼可以運(yùn)行在服務(wù)器上(如服務(wù)器激活的對(duì)象和客戶端激活的對(duì)象),然后客戶端再通過Remoting連接服務(wù)器,獲得該服務(wù)對(duì)象并通過序列化在客戶端運(yùn)行。 通道(channel)有4種嚴(yán)格說(shuō),很多資料上說(shuō)有2-3種.應(yīng)該有4種.HttpChanel和TcpChanel. (1)HttpChannel。在將遠(yuǎn)程對(duì)象駐留在 ASP.NET 中時(shí),可以使用此通道。此通道使用 HTTP 協(xié)議在客戶端和服務(wù)器之間發(fā)送消息??梢允褂肏TTP協(xié)議中的加密機(jī)制.需要主機(jī)名字和端口號(hào).
(2)TcpChannel。在將遠(yuǎn)程對(duì)象駐留在? 操作系統(tǒng)服務(wù)或其他可執(zhí)行文件中時(shí),此通道使用 TCP 套接字在客戶端和服務(wù)器之間發(fā)送消息。同樣需要提供主機(jī)名字和端口號(hào).不提供任何內(nèi)置的安全功能。 (3)IPCChanel,進(jìn)程間通道,只使用同一個(gè)系統(tǒng)內(nèi),進(jìn)程之見的通信.不需要需要主機(jī)名字和端口號(hào).
(4)自定義通道 。自定義的傳輸通道可以使用任何基本的傳輸協(xié)議UDP\SMTP\IPX\消息排隊(duì)等機(jī)制進(jìn)行通信.用戶可以根據(jù)需要自定義方式協(xié)議,因此.Net Remoting相對(duì)其他機(jī)制更加的靈活。不提供任何內(nèi)置的安全功能。 2.遠(yuǎn)程對(duì)象(Obeject) 在Remoting中要傳遞的對(duì)象,設(shè)計(jì)者除了需要了解通道的類型和端口號(hào)之外,無(wú)需再了解數(shù)據(jù)包的格式。但必須注意的是,客戶端在獲取服務(wù)器端對(duì)象時(shí),并不是獲得實(shí)際的服務(wù)端對(duì)象,而是通過代理獲得它的引用。遠(yuǎn)程對(duì)象要繼承自MarshalByRefObject類,這個(gè)可以使遠(yuǎn)程對(duì)象在remoting應(yīng)用通信中使用,支持對(duì)象的跨域邊界訪問. 3.激活方式 (1)服務(wù)器端激活,又叫做知名WellKnown方式,是因?yàn)榉?wù)器應(yīng)用程序在激活對(duì)象實(shí)例之前會(huì)在一個(gè)眾所周知的統(tǒng)一資源標(biāo)識(shí)符(URI)上來(lái)發(fā)布這個(gè)類型。然后該服務(wù)器進(jìn)程會(huì)為此類型配置一個(gè)WellKnown對(duì)象,并根據(jù)指定的端口或地址來(lái)發(fā)布對(duì)象。服務(wù)器端激活又分為SingleTon模式和SingleCall模式兩種。SingleTon模式:此為有狀態(tài)模式。如果設(shè)置為SingleTon激活方式,則Remoting將為所有客戶端建立同一個(gè)對(duì)象實(shí)例。SingleCall模式:SingleCall是一種無(wú)狀態(tài)模式。一旦設(shè)置為SingleCall模式,則當(dāng)客戶端調(diào)用遠(yuǎn)程對(duì)象的方法時(shí), Remoting會(huì)為每一個(gè)客戶端建立一個(gè)遠(yuǎn)程對(duì)象實(shí)例,至于對(duì)象實(shí)例的銷毀則是由GC自動(dòng)管理的。 (2)客戶端激活。與WellKnown模式不同, Remoting在激活每個(gè)對(duì)象實(shí)例的時(shí)候,會(huì)給每個(gè)客戶端激活的類型指派一個(gè)URI??蛻舳思せ钅J揭坏┇@得客戶端的請(qǐng)求,將為每一個(gè)客戶端都建立一個(gè)實(shí)例引用。SingleCall模式和客戶端激活模式是有區(qū)別的:首先,對(duì)象實(shí)例創(chuàng)建的時(shí)間不一樣??蛻舳思せ罘绞绞强蛻粢坏┌l(fā)出調(diào)用的請(qǐng)求,就實(shí)例化;而SingleCall則是要等到調(diào)用對(duì)象方法時(shí)再創(chuàng)建。其次,SingleCall模式激活的對(duì)象是無(wú)狀態(tài)的,對(duì)象生命期的管理是由GC管理的,而客戶端激活的對(duì)象則有狀態(tài),其生命周期可自定義。其三,兩種激活模式在服務(wù)器端和客戶端實(shí)現(xiàn)的方法不一樣。尤其是在客戶端,SingleCall模式是由 GetObject()來(lái)激活,它調(diào)用對(duì)象默認(rèn)的構(gòu)造函數(shù)。而客戶端激活模式,則通過CreateInstance()來(lái)激活,它可以傳遞參數(shù),所以可以調(diào)用自定義的構(gòu)造函數(shù)來(lái)創(chuàng)建實(shí)例。(詳細(xì)參考MSDN)
?????(4)代理Proxy,客戶端訪問的不能直接訪問遠(yuǎn)程對(duì)象,它是通過代理來(lái)訪問代理上的方法.代理對(duì)象又分為透明代理和真實(shí)代理,區(qū)別是,在透明代理上,客戶通過Invoke調(diào)用的是遠(yuǎn)程對(duì)象上真實(shí)代理的方法.然后把消息再傳遞給通道. 好了,介紹到此我們也基本了解.Net Remoting相關(guān)的知識(shí),下面我們來(lái)學(xué)習(xí)的是具體的編程實(shí)現(xiàn)部分.程序大體分為3個(gè)部分遠(yuǎn)程對(duì)象\服務(wù)器\可戶端.現(xiàn)在我們來(lái)分別實(shí)現(xiàn).服務(wù)器端要添加引用System.Runtime.Remoting的程序集. 1.遠(yuǎn)程對(duì)象(RemoteOject),也就是我們遠(yuǎn)程要訪問的對(duì)象.首先定義一個(gè)Class,繼承MarshalByRefObject,可以使用在remoting應(yīng)用中,支持對(duì)象的跨域邊界訪問.具體代碼如下: ?1namespace RemoteObject?
?2{?
?3????????//創(chuàng)建遠(yuǎn)程對(duì)象.繼承MarshalByRefObject,可以使用在remoting應(yīng)用中,支持對(duì)象的跨域邊界訪問?
?4????????public?class?MyRemoteObject : MarshalByRefObject//訪問遠(yuǎn)程對(duì)象需要通過代理?
?5????????{?
?6????????????????//簡(jiǎn)單的例子,實(shí)現(xiàn)加法功能的方法AddForTcpTest,這個(gè)遠(yuǎn)程對(duì)象可以實(shí)現(xiàn)封裝業(yè)務(wù)邏輯或者數(shù)據(jù)訪問等操作。?
?7????????????????//?
?8????????????????public?int?AddForTcpTest(int?a,?int?b)?
?9????????????????{?
10????????????????????????return?a + b;?
11????????????????}?
12????????????????//實(shí)現(xiàn)減法功能的方法MinusForHttpTest,測(cè)試HTTP通道。?
13????????????????public?int?MinusForHttpTest(int?a,?int?b)?
14????????????????{?
15????????????????????????return?a - b;?
16????????????????}?
17????????????????//實(shí)現(xiàn)乘法功能的方法MultipleForIpcTest,測(cè)試Ipc通道?
18????????????????public?int?MultipleForIpcTest(int?a,?int?b)?
19????????????????{?
20????????????????????????return?a * b;?
21????????????????}?
22????????}????
23?
24} ?????對(duì)象分別定義了3種方法,目的是為了測(cè)試3種不同的通道方式的效果.?//簡(jiǎn)單的例子,實(shí)現(xiàn)加法功能的方法AddForTcpTest,這個(gè)遠(yuǎn)程對(duì)象可以實(shí)現(xiàn)封裝業(yè)務(wù)邏輯或者數(shù)據(jù)訪問等操作。實(shí)現(xiàn)減法功能的方法MinusForHttpTest,測(cè)試HTTP通道。實(shí)現(xiàn)乘法功能的方法MultipleForIpcTest,測(cè)試Ipc通道. 2服務(wù)器端,注冊(cè)通道,以便進(jìn)程間通信,我們這里注冊(cè)了三種通道,分別是HttpChanel\TcpChanel\IPCChanel.具體代碼如下: //創(chuàng)建三種通道/
????????????///創(chuàng)建Tcp通道,使用端口10001
????????????TcpChannel?chanTcp?=?new?TcpChannel(10001);
????????????///創(chuàng)建Http通道,使用端口10002
????????????HttpChannel?chanHttp?=?new?HttpChannel(10002);
????????????///創(chuàng)建IPC通道,使用端口10003,IPC只適合同系統(tǒng)內(nèi)進(jìn)程的通信,所以不需要設(shè)置端口和主機(jī)名
????????????IpcChannel?chanIPC?=?new?IpcChannel("FrankTestIpc");
????????????//注冊(cè)通道//
????????????///注冊(cè)TCP通道
????????????ChannelServices.RegisterChannel(chanTcp);
????????????///注冊(cè)HTTP通道
????????????ChannelServices.RegisterChannel(chanHttp);
????????????///注冊(cè)IPC通道
????????????ChannelServices.RegisterChannel(chanIPC);
????????????////打印通道/
????????????//?打印TCP通道的名稱.
????????????Console.WriteLine("The?name?of?the?TCPChannel?is?{0}.",
????????????????chanTcp.ChannelName);
????????????//?打印TCP通道的優(yōu)先級(jí).
????????????Console.WriteLine("The?priority?of?the?TCPChannel?is?{0}.",
????????????????chanTcp.ChannelPriority);
????????????//?打印Http通道的名稱.
????????????Console.WriteLine("The?name?of?the?HttpChannel?is?{0}.",
????????????????chanHttp.ChannelName);
????????????//?打印Http通道的優(yōu)先級(jí).
????????????Console.WriteLine("The?priority?of?the?HttpChannel?is?{0}.",
????????????????chanHttp.ChannelPriority);
????????????//?打印IPC通道的名稱.
????????????Console.WriteLine("The?name?of?the?IpcChannel?is?{0}.",
????????????????chanIPC.ChannelName);
????????????//?打印IPC通道的優(yōu)先級(jí).
????????????Console.WriteLine("The?priority?of?the?IpcChannel?is?{0}.",
????????????????chanIPC.ChannelPriority);
????????????///注冊(cè)對(duì)象/
????????????//注冊(cè)對(duì)象MyRemoteObject到Net?Remoting運(yùn)行庫(kù)
????????????//配置遠(yuǎn)程通信基礎(chǔ)框架.第2個(gè)參數(shù)是對(duì)象的URI,“RemoteObject.MyRemoteObject”,客戶端URL一定要和這個(gè)匹配,不然會(huì)出現(xiàn)查找不到代理對(duì)象的異常
????????????RemotingConfiguration.RegisterWellKnownServiceType(typeof(RemoteObject.MyRemoteObject),?"RemoteObject.MyRemoteObject",?WellKnownObjectMode.Singleton);
????????????//遠(yuǎn)程對(duì)象激活方式是單件激活模式,每次調(diào)用共享一個(gè)對(duì)象,SingleCall激活模式會(huì)在每次調(diào)用的時(shí)候產(chǎn)生一個(gè)新對(duì)象
????????????//向信道暴露一個(gè)IPC遠(yuǎn)程對(duì)象.
????????????//RemotingConfiguration.RegisterWellKnownService(Type(typeof(RemoteObject),?"RemoteObject.rem",?System.Runtime.Remoting.WellKnownObjectMode.Singleton);
????????????///For?Debug/
????????????Console.WriteLine("Press?any?key?to?exit!");
????????????System.Console.ReadLine(); ????????????創(chuàng)建Tcp通道,使用端口10001,?創(chuàng)建Http通道,使用端口10002,創(chuàng)建IPC通道,使用端口10003,IPC只適合同系統(tǒng)內(nèi)進(jìn)程的通信,所以不需要設(shè)置端口和主機(jī)名.然后調(diào)用ChannelServices類的靜態(tài)方法RegisterChannel進(jìn)行注冊(cè).最后一步注冊(cè)對(duì)象MyRemoteObject到Net Remoting運(yùn)行庫(kù),同時(shí)要先配置遠(yuǎn)程通信基礎(chǔ)框架.第2個(gè)參數(shù)是對(duì)象的URI,“RemoteObject.MyRemoteObject”,客戶端URL一定要和這個(gè)匹配,不然會(huì)出現(xiàn)查找不到代理對(duì)象的異常.WellKnownObjectMode.Singleton);遠(yuǎn)程對(duì)象激活方式是單件激活模式,每次調(diào)用共享一個(gè)對(duì)象,SingleCall激活模式會(huì)在每次調(diào)用的時(shí)候產(chǎn)生一個(gè)新對(duì)象. 3客戶端是控制臺(tái)程序(實(shí)際項(xiàng)目類型可以替換,這里只是為了作為例子選擇控制臺(tái)類型).配置文件進(jìn)行的設(shè)置如下: ?1<configuration>?
?2????????<appSettings>?
?3????????????????<add key="ServiceURLTcp"?value="tcp://localhost:10001/RemoteObject.MyRemoteObject"/>?
?4????????????????<add key="ServiceURLHttp"?value="http://localhost:10002/RemoteObject.MyRemoteObject"/>?
?5????????????????<add key="ServiceURLIpc"?value="ipc://FrankTestIpc/RemoteObject.MyRemoteObject"/>?
?6????????</appSettings>?
?7????????<system.runtime.remoting>?
?8????????????????????????
?9???????????? </system.runtime.remoting>?
10</configuration> 配置文件設(shè)置的是具體通道的URL信息.具體c#實(shí)現(xiàn)代碼如下: 1?
?2namespace RemoteClient?
?3{?
?4????????class?MyClient//客戶端?
?5????????{?
?6????????????????[STAThread]//主線程,建立客戶端程序:注冊(cè)通道,根據(jù)URL得到對(duì)象代理,使用代理調(diào)用遠(yuǎn)程對(duì)象
?7?
?8????????????????static?void?Main(string[] args)?
?9????????????????{?
10????????????????????????//為遠(yuǎn)程對(duì)象創(chuàng)建代理?
11????????????????????????//代理的優(yōu)勢(shì)在于不僅可以跨域訪問對(duì)象還可以跨進(jìn)程,和系統(tǒng),使用TCP通道?
12????????????????????????try?
13????????????????????????{?
14????????????????????????????????/**/?
15????????????????????????????????RemoteObject.MyRemoteObject proxyObjectTcp = (RemoteObject.MyRemoteObject)Activator.GetObject(typeof(RemoteObject.MyRemoteObject), System.Configuration.ConfigurationSettings.AppSettings["ServiceURLTcp"]);?
16????????????????????????????????//通過代理訪問對(duì)象的方法,輸出結(jié)果?
17????????????????????????????????Console.WriteLine("This call object by TcpChannel,100+200 = {0}", proxyObjectTcp.AddForTcpTest(100, 200));?
18?????????????????????????????????
19????????????????????????????????/**///?
20????????????????????????????????RemoteObject.MyRemoteObject proxyObjectHttp = (RemoteObject.MyRemoteObject)Activator.GetObject(typeof(RemoteObject.MyRemoteObject), System.Configuration.ConfigurationSettings.AppSettings["ServiceURLHttp"]);?
21????????????????????????????????//通過代理訪問對(duì)象的方法,輸出結(jié)果?
22????????????????????????????????Console.WriteLine("This call object by HttpChannel,100-200 = {0}", proxyObjectHttp.MinusForHttpTest(100, 200));?
23?????????????????????????????????
24????????????????????????????????/**/ 注冊(cè)一個(gè)遠(yuǎn)程對(duì)象的客戶端代理.?
25????????????????????????????????//System.Runtime.Remoting.WellKnownClientTypeEntry remoteType = new System.Runtime.Remoting.WellKnownClientTypeEntry(typeof(RemoteObject.MyRemoteObject), "ipc://FrankTestIpc/RemoteObject.MyRemoteObject");?
26????????????????????????????????//System.Runtime.Remoting.RemotingConfiguration.RegisterWellKnownClientType(remoteType);//如果需要客戶端和住進(jìn)程通訊,要在客戶端注冊(cè)代理,方式和服務(wù)器端注冊(cè)注冊(cè)遠(yuǎn)程對(duì)象的代理相同?
27?
28????????????????????????????????RemoteObject.MyRemoteObject proxyObjectIpc = (RemoteObject.MyRemoteObject)Activator.GetObject(typeof(RemoteObject.MyRemoteObject), System.Configuration.ConfigurationSettings.AppSettings["ServiceURLIpc"]);?
29????????????????????????????????//通過代理訪問對(duì)象的方法,輸出結(jié)果?
30????????????????????????????????Console.WriteLine("This call object by IpcChannel,100*200 = {0}", proxyObjectIpc.MultipleForIpcTest(100, 200));?
31????????????????????????}?
32????????????????????????catch?(Exception e)?
33????????????????????????{?
34????????????????????????????????throw?e;?
35????????????????????????}?
36????????????????????????finally????
37????????????????????????{?
38?
39????????????????????????}?
40????????????????????????//For Debug?
41????????????????????????Console.WriteLine("Press any key to exit!");?
42????????????????????????Console.ReadLine();?
43????????????????}?
44?
45????????}?
46} 主進(jìn)程通過配置獲取遠(yuǎn)程對(duì)象的信息,為遠(yuǎn)程對(duì)象創(chuàng)建代理,代理的優(yōu)勢(shì)在于不僅可以跨域訪問對(duì)象還可以跨進(jìn)程,和系統(tǒng),使用TCP通道,降低系統(tǒng)耦合性.最后客戶端通過代理訪問遠(yuǎn)程對(duì)象的方法,輸出結(jié)果.首先要運(yùn)行服務(wù)器端,其次是客戶端,IDE使用的是Visual Studio 2005/2008.其次注意項(xiàng)目引用.運(yùn)行后的結(jié)果顯示如下. 服務(wù)器: 顯示3個(gè)通道都注冊(cè)成功. 客戶端:
??客戶端分別通過3種方式調(diào)用遠(yuǎn)程對(duì)象,進(jìn)行運(yùn)算.測(cè)試成功! 本文代碼下載./Files/frank_xl/NetRemoting.rar 小結(jié):以上就是全部的.Net Remoting的實(shí)現(xiàn)過程.當(dāng)然.Net Remoting知識(shí)范圍很廣,還有異步調(diào)用,安全等.以后再做深入的學(xué)習(xí).接下來(lái)一節(jié)我打算寫關(guān)于Enterprise Services的文章,其中會(huì)涉及到COM+的知識(shí),如COM+中事務(wù)機(jī)制.我們有必要好好學(xué)習(xí)一下.希望本文的能給大家在WCF學(xué)習(xí)上對(duì).Net Remoting技術(shù)的理解有所幫助.大家有問題可以一起交流~
本文轉(zhuǎn)自 frankxulei 51CTO博客,原文鏈接:http://blog.51cto.com/frankxulei/320394,如需轉(zhuǎn)載請(qǐng)自行聯(lián)系原作者
(2)TcpChannel。在將遠(yuǎn)程對(duì)象駐留在? 操作系統(tǒng)服務(wù)或其他可執(zhí)行文件中時(shí),此通道使用 TCP 套接字在客戶端和服務(wù)器之間發(fā)送消息。同樣需要提供主機(jī)名字和端口號(hào).不提供任何內(nèi)置的安全功能。 (3)IPCChanel,進(jìn)程間通道,只使用同一個(gè)系統(tǒng)內(nèi),進(jìn)程之見的通信.不需要需要主機(jī)名字和端口號(hào).
(4)自定義通道 。自定義的傳輸通道可以使用任何基本的傳輸協(xié)議UDP\SMTP\IPX\消息排隊(duì)等機(jī)制進(jìn)行通信.用戶可以根據(jù)需要自定義方式協(xié)議,因此.Net Remoting相對(duì)其他機(jī)制更加的靈活。不提供任何內(nèi)置的安全功能。 2.遠(yuǎn)程對(duì)象(Obeject) 在Remoting中要傳遞的對(duì)象,設(shè)計(jì)者除了需要了解通道的類型和端口號(hào)之外,無(wú)需再了解數(shù)據(jù)包的格式。但必須注意的是,客戶端在獲取服務(wù)器端對(duì)象時(shí),并不是獲得實(shí)際的服務(wù)端對(duì)象,而是通過代理獲得它的引用。遠(yuǎn)程對(duì)象要繼承自MarshalByRefObject類,這個(gè)可以使遠(yuǎn)程對(duì)象在remoting應(yīng)用通信中使用,支持對(duì)象的跨域邊界訪問. 3.激活方式 (1)服務(wù)器端激活,又叫做知名WellKnown方式,是因?yàn)榉?wù)器應(yīng)用程序在激活對(duì)象實(shí)例之前會(huì)在一個(gè)眾所周知的統(tǒng)一資源標(biāo)識(shí)符(URI)上來(lái)發(fā)布這個(gè)類型。然后該服務(wù)器進(jìn)程會(huì)為此類型配置一個(gè)WellKnown對(duì)象,并根據(jù)指定的端口或地址來(lái)發(fā)布對(duì)象。服務(wù)器端激活又分為SingleTon模式和SingleCall模式兩種。SingleTon模式:此為有狀態(tài)模式。如果設(shè)置為SingleTon激活方式,則Remoting將為所有客戶端建立同一個(gè)對(duì)象實(shí)例。SingleCall模式:SingleCall是一種無(wú)狀態(tài)模式。一旦設(shè)置為SingleCall模式,則當(dāng)客戶端調(diào)用遠(yuǎn)程對(duì)象的方法時(shí), Remoting會(huì)為每一個(gè)客戶端建立一個(gè)遠(yuǎn)程對(duì)象實(shí)例,至于對(duì)象實(shí)例的銷毀則是由GC自動(dòng)管理的。 (2)客戶端激活。與WellKnown模式不同, Remoting在激活每個(gè)對(duì)象實(shí)例的時(shí)候,會(huì)給每個(gè)客戶端激活的類型指派一個(gè)URI??蛻舳思せ钅J揭坏┇@得客戶端的請(qǐng)求,將為每一個(gè)客戶端都建立一個(gè)實(shí)例引用。SingleCall模式和客戶端激活模式是有區(qū)別的:首先,對(duì)象實(shí)例創(chuàng)建的時(shí)間不一樣??蛻舳思せ罘绞绞强蛻粢坏┌l(fā)出調(diào)用的請(qǐng)求,就實(shí)例化;而SingleCall則是要等到調(diào)用對(duì)象方法時(shí)再創(chuàng)建。其次,SingleCall模式激活的對(duì)象是無(wú)狀態(tài)的,對(duì)象生命期的管理是由GC管理的,而客戶端激活的對(duì)象則有狀態(tài),其生命周期可自定義。其三,兩種激活模式在服務(wù)器端和客戶端實(shí)現(xiàn)的方法不一樣。尤其是在客戶端,SingleCall模式是由 GetObject()來(lái)激活,它調(diào)用對(duì)象默認(rèn)的構(gòu)造函數(shù)。而客戶端激活模式,則通過CreateInstance()來(lái)激活,它可以傳遞參數(shù),所以可以調(diào)用自定義的構(gòu)造函數(shù)來(lái)創(chuàng)建實(shí)例。(詳細(xì)參考MSDN)
?????(4)代理Proxy,客戶端訪問的不能直接訪問遠(yuǎn)程對(duì)象,它是通過代理來(lái)訪問代理上的方法.代理對(duì)象又分為透明代理和真實(shí)代理,區(qū)別是,在透明代理上,客戶通過Invoke調(diào)用的是遠(yuǎn)程對(duì)象上真實(shí)代理的方法.然后把消息再傳遞給通道. 好了,介紹到此我們也基本了解.Net Remoting相關(guān)的知識(shí),下面我們來(lái)學(xué)習(xí)的是具體的編程實(shí)現(xiàn)部分.程序大體分為3個(gè)部分遠(yuǎn)程對(duì)象\服務(wù)器\可戶端.現(xiàn)在我們來(lái)分別實(shí)現(xiàn).服務(wù)器端要添加引用System.Runtime.Remoting的程序集. 1.遠(yuǎn)程對(duì)象(RemoteOject),也就是我們遠(yuǎn)程要訪問的對(duì)象.首先定義一個(gè)Class,繼承MarshalByRefObject,可以使用在remoting應(yīng)用中,支持對(duì)象的跨域邊界訪問.具體代碼如下: ?1namespace RemoteObject?
?2{?
?3????????//創(chuàng)建遠(yuǎn)程對(duì)象.繼承MarshalByRefObject,可以使用在remoting應(yīng)用中,支持對(duì)象的跨域邊界訪問?
?4????????public?class?MyRemoteObject : MarshalByRefObject//訪問遠(yuǎn)程對(duì)象需要通過代理?
?5????????{?
?6????????????????//簡(jiǎn)單的例子,實(shí)現(xiàn)加法功能的方法AddForTcpTest,這個(gè)遠(yuǎn)程對(duì)象可以實(shí)現(xiàn)封裝業(yè)務(wù)邏輯或者數(shù)據(jù)訪問等操作。?
?7????????????????//?
?8????????????????public?int?AddForTcpTest(int?a,?int?b)?
?9????????????????{?
10????????????????????????return?a + b;?
11????????????????}?
12????????????????//實(shí)現(xiàn)減法功能的方法MinusForHttpTest,測(cè)試HTTP通道。?
13????????????????public?int?MinusForHttpTest(int?a,?int?b)?
14????????????????{?
15????????????????????????return?a - b;?
16????????????????}?
17????????????????//實(shí)現(xiàn)乘法功能的方法MultipleForIpcTest,測(cè)試Ipc通道?
18????????????????public?int?MultipleForIpcTest(int?a,?int?b)?
19????????????????{?
20????????????????????????return?a * b;?
21????????????????}?
22????????}????
23?
24} ?????對(duì)象分別定義了3種方法,目的是為了測(cè)試3種不同的通道方式的效果.?//簡(jiǎn)單的例子,實(shí)現(xiàn)加法功能的方法AddForTcpTest,這個(gè)遠(yuǎn)程對(duì)象可以實(shí)現(xiàn)封裝業(yè)務(wù)邏輯或者數(shù)據(jù)訪問等操作。實(shí)現(xiàn)減法功能的方法MinusForHttpTest,測(cè)試HTTP通道。實(shí)現(xiàn)乘法功能的方法MultipleForIpcTest,測(cè)試Ipc通道. 2服務(wù)器端,注冊(cè)通道,以便進(jìn)程間通信,我們這里注冊(cè)了三種通道,分別是HttpChanel\TcpChanel\IPCChanel.具體代碼如下: //創(chuàng)建三種通道/
????????????///創(chuàng)建Tcp通道,使用端口10001
????????????TcpChannel?chanTcp?=?new?TcpChannel(10001);
????????????///創(chuàng)建Http通道,使用端口10002
????????????HttpChannel?chanHttp?=?new?HttpChannel(10002);
????????????///創(chuàng)建IPC通道,使用端口10003,IPC只適合同系統(tǒng)內(nèi)進(jìn)程的通信,所以不需要設(shè)置端口和主機(jī)名
????????????IpcChannel?chanIPC?=?new?IpcChannel("FrankTestIpc");
????????????//注冊(cè)通道//
????????????///注冊(cè)TCP通道
????????????ChannelServices.RegisterChannel(chanTcp);
????????????///注冊(cè)HTTP通道
????????????ChannelServices.RegisterChannel(chanHttp);
????????????///注冊(cè)IPC通道
????????????ChannelServices.RegisterChannel(chanIPC);
????????????////打印通道/
????????????//?打印TCP通道的名稱.
????????????Console.WriteLine("The?name?of?the?TCPChannel?is?{0}.",
????????????????chanTcp.ChannelName);
????????????//?打印TCP通道的優(yōu)先級(jí).
????????????Console.WriteLine("The?priority?of?the?TCPChannel?is?{0}.",
????????????????chanTcp.ChannelPriority);
????????????//?打印Http通道的名稱.
????????????Console.WriteLine("The?name?of?the?HttpChannel?is?{0}.",
????????????????chanHttp.ChannelName);
????????????//?打印Http通道的優(yōu)先級(jí).
????????????Console.WriteLine("The?priority?of?the?HttpChannel?is?{0}.",
????????????????chanHttp.ChannelPriority);
????????????//?打印IPC通道的名稱.
????????????Console.WriteLine("The?name?of?the?IpcChannel?is?{0}.",
????????????????chanIPC.ChannelName);
????????????//?打印IPC通道的優(yōu)先級(jí).
????????????Console.WriteLine("The?priority?of?the?IpcChannel?is?{0}.",
????????????????chanIPC.ChannelPriority);
????????????///注冊(cè)對(duì)象/
????????????//注冊(cè)對(duì)象MyRemoteObject到Net?Remoting運(yùn)行庫(kù)
????????????//配置遠(yuǎn)程通信基礎(chǔ)框架.第2個(gè)參數(shù)是對(duì)象的URI,“RemoteObject.MyRemoteObject”,客戶端URL一定要和這個(gè)匹配,不然會(huì)出現(xiàn)查找不到代理對(duì)象的異常
????????????RemotingConfiguration.RegisterWellKnownServiceType(typeof(RemoteObject.MyRemoteObject),?"RemoteObject.MyRemoteObject",?WellKnownObjectMode.Singleton);
????????????//遠(yuǎn)程對(duì)象激活方式是單件激活模式,每次調(diào)用共享一個(gè)對(duì)象,SingleCall激活模式會(huì)在每次調(diào)用的時(shí)候產(chǎn)生一個(gè)新對(duì)象
????????????//向信道暴露一個(gè)IPC遠(yuǎn)程對(duì)象.
????????????//RemotingConfiguration.RegisterWellKnownService(Type(typeof(RemoteObject),?"RemoteObject.rem",?System.Runtime.Remoting.WellKnownObjectMode.Singleton);
????????????///For?Debug/
????????????Console.WriteLine("Press?any?key?to?exit!");
????????????System.Console.ReadLine(); ????????????創(chuàng)建Tcp通道,使用端口10001,?創(chuàng)建Http通道,使用端口10002,創(chuàng)建IPC通道,使用端口10003,IPC只適合同系統(tǒng)內(nèi)進(jìn)程的通信,所以不需要設(shè)置端口和主機(jī)名.然后調(diào)用ChannelServices類的靜態(tài)方法RegisterChannel進(jìn)行注冊(cè).最后一步注冊(cè)對(duì)象MyRemoteObject到Net Remoting運(yùn)行庫(kù),同時(shí)要先配置遠(yuǎn)程通信基礎(chǔ)框架.第2個(gè)參數(shù)是對(duì)象的URI,“RemoteObject.MyRemoteObject”,客戶端URL一定要和這個(gè)匹配,不然會(huì)出現(xiàn)查找不到代理對(duì)象的異常.WellKnownObjectMode.Singleton);遠(yuǎn)程對(duì)象激活方式是單件激活模式,每次調(diào)用共享一個(gè)對(duì)象,SingleCall激活模式會(huì)在每次調(diào)用的時(shí)候產(chǎn)生一個(gè)新對(duì)象. 3客戶端是控制臺(tái)程序(實(shí)際項(xiàng)目類型可以替換,這里只是為了作為例子選擇控制臺(tái)類型).配置文件進(jìn)行的設(shè)置如下: ?1<configuration>?
?2????????<appSettings>?
?3????????????????<add key="ServiceURLTcp"?value="tcp://localhost:10001/RemoteObject.MyRemoteObject"/>?
?4????????????????<add key="ServiceURLHttp"?value="http://localhost:10002/RemoteObject.MyRemoteObject"/>?
?5????????????????<add key="ServiceURLIpc"?value="ipc://FrankTestIpc/RemoteObject.MyRemoteObject"/>?
?6????????</appSettings>?
?7????????<system.runtime.remoting>?
?8????????????????????????
?9???????????? </system.runtime.remoting>?
10</configuration> 配置文件設(shè)置的是具體通道的URL信息.具體c#實(shí)現(xiàn)代碼如下: 1?
?2namespace RemoteClient?
?3{?
?4????????class?MyClient//客戶端?
?5????????{?
?6????????????????[STAThread]//主線程,建立客戶端程序:注冊(cè)通道,根據(jù)URL得到對(duì)象代理,使用代理調(diào)用遠(yuǎn)程對(duì)象
?7?
?8????????????????static?void?Main(string[] args)?
?9????????????????{?
10????????????????????????//為遠(yuǎn)程對(duì)象創(chuàng)建代理?
11????????????????????????//代理的優(yōu)勢(shì)在于不僅可以跨域訪問對(duì)象還可以跨進(jìn)程,和系統(tǒng),使用TCP通道?
12????????????????????????try?
13????????????????????????{?
14????????????????????????????????/**/?
15????????????????????????????????RemoteObject.MyRemoteObject proxyObjectTcp = (RemoteObject.MyRemoteObject)Activator.GetObject(typeof(RemoteObject.MyRemoteObject), System.Configuration.ConfigurationSettings.AppSettings["ServiceURLTcp"]);?
16????????????????????????????????//通過代理訪問對(duì)象的方法,輸出結(jié)果?
17????????????????????????????????Console.WriteLine("This call object by TcpChannel,100+200 = {0}", proxyObjectTcp.AddForTcpTest(100, 200));?
18?????????????????????????????????
19????????????????????????????????/**///?
20????????????????????????????????RemoteObject.MyRemoteObject proxyObjectHttp = (RemoteObject.MyRemoteObject)Activator.GetObject(typeof(RemoteObject.MyRemoteObject), System.Configuration.ConfigurationSettings.AppSettings["ServiceURLHttp"]);?
21????????????????????????????????//通過代理訪問對(duì)象的方法,輸出結(jié)果?
22????????????????????????????????Console.WriteLine("This call object by HttpChannel,100-200 = {0}", proxyObjectHttp.MinusForHttpTest(100, 200));?
23?????????????????????????????????
24????????????????????????????????/**/ 注冊(cè)一個(gè)遠(yuǎn)程對(duì)象的客戶端代理.?
25????????????????????????????????//System.Runtime.Remoting.WellKnownClientTypeEntry remoteType = new System.Runtime.Remoting.WellKnownClientTypeEntry(typeof(RemoteObject.MyRemoteObject), "ipc://FrankTestIpc/RemoteObject.MyRemoteObject");?
26????????????????????????????????//System.Runtime.Remoting.RemotingConfiguration.RegisterWellKnownClientType(remoteType);//如果需要客戶端和住進(jìn)程通訊,要在客戶端注冊(cè)代理,方式和服務(wù)器端注冊(cè)注冊(cè)遠(yuǎn)程對(duì)象的代理相同?
27?
28????????????????????????????????RemoteObject.MyRemoteObject proxyObjectIpc = (RemoteObject.MyRemoteObject)Activator.GetObject(typeof(RemoteObject.MyRemoteObject), System.Configuration.ConfigurationSettings.AppSettings["ServiceURLIpc"]);?
29????????????????????????????????//通過代理訪問對(duì)象的方法,輸出結(jié)果?
30????????????????????????????????Console.WriteLine("This call object by IpcChannel,100*200 = {0}", proxyObjectIpc.MultipleForIpcTest(100, 200));?
31????????????????????????}?
32????????????????????????catch?(Exception e)?
33????????????????????????{?
34????????????????????????????????throw?e;?
35????????????????????????}?
36????????????????????????finally????
37????????????????????????{?
38?
39????????????????????????}?
40????????????????????????//For Debug?
41????????????????????????Console.WriteLine("Press any key to exit!");?
42????????????????????????Console.ReadLine();?
43????????????????}?
44?
45????????}?
46} 主進(jìn)程通過配置獲取遠(yuǎn)程對(duì)象的信息,為遠(yuǎn)程對(duì)象創(chuàng)建代理,代理的優(yōu)勢(shì)在于不僅可以跨域訪問對(duì)象還可以跨進(jìn)程,和系統(tǒng),使用TCP通道,降低系統(tǒng)耦合性.最后客戶端通過代理訪問遠(yuǎn)程對(duì)象的方法,輸出結(jié)果.首先要運(yùn)行服務(wù)器端,其次是客戶端,IDE使用的是Visual Studio 2005/2008.其次注意項(xiàng)目引用.運(yùn)行后的結(jié)果顯示如下. 服務(wù)器: 顯示3個(gè)通道都注冊(cè)成功. 客戶端:
??客戶端分別通過3種方式調(diào)用遠(yuǎn)程對(duì)象,進(jìn)行運(yùn)算.測(cè)試成功! 本文代碼下載./Files/frank_xl/NetRemoting.rar 小結(jié):以上就是全部的.Net Remoting的實(shí)現(xiàn)過程.當(dāng)然.Net Remoting知識(shí)范圍很廣,還有異步調(diào)用,安全等.以后再做深入的學(xué)習(xí).接下來(lái)一節(jié)我打算寫關(guān)于Enterprise Services的文章,其中會(huì)涉及到COM+的知識(shí),如COM+中事務(wù)機(jī)制.我們有必要好好學(xué)習(xí)一下.希望本文的能給大家在WCF學(xué)習(xí)上對(duì).Net Remoting技術(shù)的理解有所幫助.大家有問題可以一起交流~
本文轉(zhuǎn)自 frankxulei 51CTO博客,原文鏈接:http://blog.51cto.com/frankxulei/320394,如需轉(zhuǎn)載請(qǐng)自行聯(lián)系原作者
總結(jié)
以上是生活随笔為你收集整理的WCF分布式开发必备知识(2):.Net Remoting的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 78、VLAN间路由配置实验之单臂路由
- 下一篇: CentOS上安装skype