WCF和Remoting之間的消息傳輸
一.NET Remoting 介紹
簡(jiǎn)介
.NET Remoting與MSMQ不同,它不支持離線(xiàn)可得,另外只適合.NET平臺(tái)的程序進(jìn)行通信。它提供了一種允許對(duì)象通過(guò)應(yīng)用程序域與另一個(gè)對(duì)象進(jìn)行交互的框架。.NET 應(yīng)用程序都在一個(gè)主應(yīng)用程序域中執(zhí)行的,在一個(gè)應(yīng)用程序域中的代碼不能訪(fǎng)問(wèn)另一個(gè)應(yīng)用程序域的數(shù)據(jù),然而在某些情況下,我們需要跨應(yīng)用程序域,與另外的應(yīng)用程序域進(jìn)行通信,這時(shí)候就可以采用.NET Remoting技術(shù)來(lái)實(shí)現(xiàn)與另一個(gè)程序域中的對(duì)象進(jìn)行交互。
基本原理
.NET Remoting技術(shù)是通過(guò)通道來(lái)實(shí)現(xiàn)兩個(gè)應(yīng)用程序之間對(duì)象的通信的。
首先,客戶(hù)端通過(guò)Remoting技術(shù)的訪(fǎng)問(wèn)通道來(lái)獲得服務(wù)器端對(duì)象,再通過(guò)代理解析為客戶(hù)端對(duì)象,也稱(chēng)作透明代理,此時(shí)獲得客戶(hù)端對(duì)象只是服務(wù)器對(duì)象的一個(gè)引用。這既保證了客戶(hù)端和服務(wù)端有關(guān)對(duì)象的松散耦合,同時(shí)優(yōu)化了通信的性能。在這個(gè)過(guò)程中,當(dāng)客戶(hù)端通過(guò)透明代理來(lái)調(diào)用遠(yuǎn)程對(duì)象的方法時(shí),此時(shí)會(huì)將調(diào)用封裝到一個(gè)消息對(duì)象中,該消息對(duì)象包括遠(yuǎn)程對(duì)象信息,被調(diào)用的方法名和參數(shù),然后透明代理會(huì)將調(diào)用委托給真實(shí)代理(RealProxy對(duì)象)的Invoke方法來(lái)生成一個(gè)IMethodCallMessage,
接著通過(guò)序列化把這個(gè)消息對(duì)象序列化成數(shù)據(jù)流發(fā)送到通道,通道會(huì)把數(shù)據(jù)流傳送到服務(wù)器端。當(dāng)服務(wù)器接收到經(jīng)過(guò)格式化的數(shù)據(jù)之后,首先從中通過(guò)反序列化來(lái)還原消息對(duì)象,之后在服務(wù)器端來(lái)激活遠(yuǎn)程對(duì)象,并調(diào)用對(duì)應(yīng)的方法,而方法的返回結(jié)果過(guò)程則是按照之前的方法反向重復(fù)一遍。具體的實(shí)現(xiàn)原理圖如下所示:
遠(yuǎn)程對(duì)象:
是運(yùn)行在服務(wù)器端的對(duì)象,客戶(hù)端不能直接調(diào)用,由于.NET Remoting傳遞的對(duì)象是以引用的方式,因此所傳遞的遠(yuǎn)程對(duì)象必須繼承MarshalByRefObject類(lèi),這個(gè)類(lèi)可以使遠(yuǎn)程對(duì)象在.NET Remoting應(yīng)用通信中使用,支持對(duì)象的跨域邊界訪(fǎng)問(wèn)。
遠(yuǎn)程對(duì)象的激活方式
在訪(fǎng)問(wèn)服務(wù)器端的一個(gè)對(duì)象實(shí)例之前,必須通過(guò)一個(gè)名為Activation的進(jìn)程創(chuàng)建它并進(jìn)行初始化。這種客戶(hù)端通過(guò)通道來(lái)創(chuàng)建遠(yuǎn)程對(duì)象的方式稱(chēng)為對(duì)象的激活。在.NET Remoting中,遠(yuǎn)程對(duì)象的激活分為兩大類(lèi):服務(wù)器端激活和客戶(hù)端激活。
1、服務(wù)器端激活(WellKnow(知名對(duì)象)激活模式)
為什么稱(chēng)為知名對(duì)象激活模式呢?是因?yàn)榉?wù)應(yīng)用程序在激活對(duì)象實(shí)例之前會(huì)在一個(gè)眾所周知的統(tǒng)一資源標(biāo)示符(URI)上發(fā)布這個(gè)類(lèi)型,然后該服務(wù)器進(jìn)行會(huì)為此類(lèi)型配置一個(gè)WellKnow對(duì)象,并根據(jù)指定的端口或地址來(lái)發(fā)布對(duì)象。
.NET Remoting把服務(wù)器端激活又分為SingleTon模式和SingleCall模式兩種。
- SingleTon模式:此為有狀態(tài)模式。.NET Remoting將為所有客戶(hù)端建立同一個(gè)對(duì)象實(shí)例。服務(wù)端只在對(duì)象第一次被調(diào)用時(shí)創(chuàng)建服務(wù)對(duì)象,當(dāng)對(duì)象處于活動(dòng)狀態(tài)時(shí),SingleTon實(shí)例會(huì)處理所有后來(lái)的客戶(hù)端訪(fǎng)問(wèn)請(qǐng)求,而不管它們是同一個(gè)客戶(hù)端,還是其他客戶(hù)端。SingleTon實(shí)例將在方法調(diào)用中一直維護(hù)其狀態(tài),類(lèi)似static成員的概念。(相當(dāng)于Application狀態(tài))
- SingleCall模式:是一種無(wú)狀態(tài)模式。則當(dāng)客戶(hù)端調(diào)用遠(yuǎn)程對(duì)象的方法時(shí),Remoting會(huì)為每一個(gè)客戶(hù)端建立一個(gè)遠(yuǎn)程對(duì)象實(shí)例,對(duì)象實(shí)例的銷(xiāo)毀則是由GC自動(dòng)管理。類(lèi)似實(shí)例成員的概念。(相當(dāng)于Session狀態(tài))
2、客戶(hù)端激活:
與Wellknow模式不同,。NET Remoting在激活每個(gè)對(duì)象實(shí)例的時(shí)候,會(huì)給每個(gè)客戶(hù)端激活的類(lèi)型指派一個(gè)URI??蛻?hù)端激活模式一旦獲得客戶(hù)端的請(qǐng)求,將為每一個(gè)客戶(hù)端都建立一個(gè)實(shí)例引用。SingleCall模式與客戶(hù)端激活模式的區(qū)別有:
首先,對(duì)象實(shí)例創(chuàng)建的時(shí)間不同??蛻?hù)端激活方式是客戶(hù)一旦發(fā)出調(diào)用請(qǐng)求就實(shí)例化,而SingleCall則要等到調(diào)用對(duì)象方法時(shí)再創(chuàng)建。
其次,SingleCall模式激活的對(duì)象是無(wú)狀態(tài)的,對(duì)象聲明周期由GC管理,而客戶(hù)端激活的對(duì)象是有狀態(tài)的,其生命周期可自定義。
第三,兩種激活模式在服務(wù)器端和客戶(hù)端實(shí)現(xiàn)的方法不一樣,尤其是在客戶(hù)端,SingleCall模式由GetObject()來(lái)激活,它調(diào)用對(duì)象默認(rèn)的構(gòu)造函數(shù),而客戶(hù)端激活模式,則通過(guò)CreateInstance()來(lái)激活,它可以傳遞參數(shù),所以可以調(diào)用自定義的構(gòu)造函數(shù)來(lái)創(chuàng)建實(shí)例。
通道:
在.NET Remoting中時(shí)通過(guò)通道來(lái)實(shí)現(xiàn)兩個(gè)應(yīng)用程序域之間對(duì)象的通信。.NET Remoting中包括4中通道類(lèi)型:
- TcpChannel:Tcp通道使用Tcp協(xié)議來(lái)跨越.Net Remoting邊界來(lái)傳輸序列化的消息流,TcpChannel默認(rèn)使用二進(jìn)制格式序列化消息對(duì)象,因此具有更高的傳輸性能,但不提供任何內(nèi)置的安全功能。
- HttpChannel:Http通道使用Http協(xié)議在客戶(hù)端和服務(wù)器之間發(fā)生消息,使其在Internet上穿越防火墻來(lái)傳輸序列化的消息流。默認(rèn)情況下,HttpChannel使用Soap格式序列化消息對(duì)象,因此它具有更好的互操作性,并且可以使用Http協(xié)議中的加密機(jī)制來(lái)對(duì)消息進(jìn)行加密來(lái)保證安全性。因此,通常在局域網(wǎng)內(nèi),我們更多地使用TcpChannel,如果要穿越防火墻,則使用HttpChannel。
- IpcChannel:進(jìn)程間通信,只使用同一個(gè)系統(tǒng)進(jìn)程之間的通信,不需要主機(jī)名和端口號(hào)。而使用Http通道和Tcp通道都要指定主機(jī)名和端口號(hào)。
- 自定義通道:自定義的傳輸通道可以使用任何基本的傳輸協(xié)議來(lái)進(jìn)行通信,如UDP協(xié)議、SMTP協(xié)議等。
二、服務(wù)端激活方式:SAO
1、創(chuàng)建一個(gè)共享接口的dll,服務(wù)端和客戶(hù)端都要引用它。
//定義接口類(lèi)ITax //編譯生成ITaxTemoting.dll //服務(wù)器端和客戶(hù)端都要添加該類(lèi)dll的引用 public interface ITax { double GetTax(int salary); }
創(chuàng)建遠(yuǎn)程對(duì)象,該對(duì)象必須繼承MarshalByRefObject對(duì)象。遠(yuǎn)程對(duì)象類(lèi)Tax繼承了基類(lèi)MarshalByRefObject和接口ITax。
//定義遠(yuǎn)程對(duì)象,必須繼承自MarshalByRefObject //編譯生成TaxRemoting.dll,服務(wù)器端必須添加該dll的引用 public class Tax : MarshalByRefObject, ITax { private int _callOCunt = 0; public Tax() { Console.WriteLine("Remoting object Tax 已激活"); } //根據(jù)稅 public double GetTax(int salary) { _callOCunt++; return (double)tax; } }
2、服務(wù)端
需要添加System.Runtime.Remoting.dll引用
定義通道并監(jiān)聽(tīng),注冊(cè)遠(yuǎn)程對(duì)象。信道用于.NET客戶(hù)端和服務(wù)器端的通信。
在.NET Remoting中,是允許同時(shí)創(chuàng)建多個(gè)通道的,但是.NET Remoting要求通道的名字必須不同,因?yàn)槊质怯脕?lái)標(biāo)識(shí)通道的唯一標(biāo)識(shí)符。
TcpChannel channel = new TcpChannel(8085);//定義通道,還有HttpChannel\IPCChannel等 ChannelServices.RegisterChannel(channel, false);//注冊(cè)通道 RemotingConfiguration.RegisterWellKnownServiceType(typeof(Tax), "Tax1", WellKnownObjectMode.SingleCall); //在服務(wù)端注冊(cè)一個(gè)知名的遠(yuǎn)程對(duì)象Tax,ObjectURI為T(mén)ax,知名對(duì)象模式為單次調(diào)用方式。
3、客戶(hù)端
注冊(cè)信道,根據(jù)URL獲取遠(yuǎn)程對(duì)象代理,使用代理調(diào)用服務(wù)器端的遠(yuǎn)程對(duì)象。
void Main() { TcpChannel channel = new TcpChannel(); ChannelServices.RegisterChannel(channel, false); ITax obj = (ITax)Activator.GetObject(typeof(ITax), "tcp://localhost:8085/Tax1");//根據(jù)URL獲取遠(yuǎn)程對(duì)象代理,使用此代理調(diào)用服務(wù)端的遠(yuǎn)程對(duì)象。 if (obj == null) { Console.WriteLine("Could not locate TCP server"); } Console.WriteLine(obj.GetTax(1).ToString());//調(diào)用遠(yuǎn)程對(duì)象的方法獲取結(jié)果,此時(shí)調(diào)用服務(wù)端的類(lèi)的默認(rèn)構(gòu)造函數(shù)實(shí)例化。 Console.WriteLine(obj.GetCallCount().ToString()); Console.WriteLine(obj.GetTax(1).ToString()); Console.WriteLine(obj.GetCallCount().ToString()); } //也可以先為客戶(hù)端注冊(cè)類(lèi)型,再實(shí)例化對(duì)象(不推薦) RemotingConfiguration.RegisterWellKnownClientType(typeof(ITax), "tcp://localhost:8085/Tax1"); Tax obj = new Tax(); obj.GetTax();
三、客戶(hù)端激活方式:CAO
可以調(diào)用服務(wù)端非默認(rèn)的帶參數(shù)的構(gòu)造函數(shù),服務(wù)端為每個(gè)客戶(hù)端保存不同的狀態(tài)。
1、聲明定義一個(gè)公共類(lèi)
public class Tax : MarshalByRefObject, ITax { //代碼同服務(wù)端SAO }
2、服務(wù)端,應(yīng)用Tax所在的程序集
TcpChannel channel = new TcpChannel(8085); ChannelServices.RegisterChannel(channel, false); RemotingConfiguration.ApplicationName = "Tax1"; RemotingConfiguration.RegisterActivatedServiceType(typeof(Tax));
3、客戶(hù)端
可以使用Soapsuds.exe分離Tax程序集共客戶(hù)端調(diào)用(即不包含具體的實(shí)現(xiàn)內(nèi)容)
E:>soapsuds -url:http://127.0.0.1:8502/TaxTax1?wsdl -oa:ClientProxy.dll
這將為我們?cè)贓盤(pán)的根目錄下生成ClientProxy.dll文件,這個(gè)文件將用于客戶(hù)端成生代理。
void Main() { TcpChannel channel = new TcpChannel(); ChannelServices.RegisterChannel(channel, false); Tax obj = (Tax)Activator.CreateInstance(typeof(ITax), null, new[] {new UrlAttribute ("tcp://localhost:8085/Tax1")});//根據(jù)URL獲取遠(yuǎn)程對(duì)象代理,使用此代理調(diào)用服務(wù)端的遠(yuǎn)程對(duì)象。 Console.WriteLine(obj.GetTax(1).ToString()); Console.WriteLine(obj.GetCallCount().ToString()); Console.WriteLine(obj.GetTax(1).ToString()); Console.WriteLine(obj.GetCallCount().ToString()); } //也可以先為客戶(hù)端注冊(cè)類(lèi)型,再實(shí)例化對(duì)象(不推薦) RemotingConfiguration.RegisterActivatedClientType(typeof(ITax), "tcp://localhost:8085/Tax1");//Activator.GetObject Tax obj = new Tax(); obj.GetTax();
4、關(guān)閉注銷(xiāo)通道
channel.StartListening(null); ChannelServices.UnregisterChannel(channel);
四、使用配置文件來(lái)重寫(xiě)上面的分布式程序
服務(wù)端:
RemotingConfiguration.Configure("RemotingServerHostByConfig.exe.config", false);
服務(wù)端的配置文件app.config的內(nèi)容為
<configuration> <system.runtime.remoting> <application> <service> <!--服務(wù)端,如果是客戶(hù)端改成Client –> <wellknown type="Tax" objectUri="Tax1" mode="SingleCall" /> <!--客戶(hù)端激活改成activator—> </service> <channels> <channel ref="tcp" port="8085" /> </channels> </application> </configuration>
客戶(hù)端:
RemotingConfiguration.Configure("RemotingClientByConfig.exe.config", false);
客戶(hù)端配置文件的內(nèi)容為:
<?xml version="1.0" encoding="utf-8" ?> <configuration> <system.runtime.remoting> <application> <client> <wellknown type="Tax" url="tcp://localhost:8085/Tax1" /> </client> <channels> <channel ref="tcp" port="8085"></channel> </channels> </application> </system.runtime.remoting> </configuration>
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- C# NetRemoting實(shí)現(xiàn)雙向通信
- Remoting和Webservice的詳細(xì)介紹及區(qū)別
- Microsoft .Net Remoting系列教程之三:Remoting事件處理全接觸
- Microsoft .Net Remoting系列教程之二:Marshal、Disconnect與生命周期以及跟蹤服務(wù)
- Microsoft .Net Remoting系列教程之一:.Net Remoting基礎(chǔ)篇
- Flex 錯(cuò)誤(mx.messaging.messages::RemotingMessage)分析
- ASP.NET通過(guò)Remoting service上傳文件
相關(guān)文章
C# 解決datagridview控件顯示大量數(shù)據(jù)拖拉卡頓問(wèn)題
這篇文章主要介紹了C# 解決datagridview控件顯示大量數(shù)據(jù)拖拉卡頓問(wèn)題,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01C# ListView 點(diǎn)擊表頭對(duì)數(shù)據(jù)進(jìn)行排序功能的實(shí)現(xiàn)代碼
這篇文章主要介紹了C# ListView 點(diǎn)擊表頭對(duì)數(shù)據(jù)進(jìn)行排序功能的實(shí)現(xiàn)代碼,需要的朋友可以參考下2017-04-04DevExpress實(shí)現(xiàn)禁用TreeListNode CheckBox的方法
這篇文章主要介紹了DevExpress實(shí)現(xiàn)禁用TreeListNode CheckBox的方法,在項(xiàng)目開(kāi)發(fā)中有應(yīng)用價(jià)值,需要的朋友可以參考下2014-08-08