這幾天看了不少Remoting文章。明白了不少技術細節,但困惑也不少。簡單說來,Remoting是一個分布式處理服務。服務器端首先創建通道(Channel),并自動開啟監聽通道。根據客戶端發出的請求,傳遞遠程對象。
因此,編寫Remoting程序,主要分為三部分:
1、被傳遞的遠程對象;
2、服務器端監聽程序;
3、客戶端請求和處理對象程序;
一、被傳遞的遠程對象
在Remoting中,被傳遞的遠程對象類是有諸多限制的。首先,我們必須清楚,這里所謂的傳遞是以引用的方式,因此所傳遞的遠程對象類必須繼承MarshalByRefObject。
MarshalByRefObject
是那些通過使用代理交換消息來跨越應用程序域邊界進行通信的對象的基類。不是從
MarshalByRefObject
繼承的對象會以隱式方式按值封送。當遠程應用程序引用一個按值封送的對象時,將跨越遠程處理邊界傳遞該對象的副本。因為您希望使用代理方法而不是副本方法進行通信,因此需要繼承
MarshallByRefObject
。(MSDN)











這個類只實現了最簡單的方法,就是設置一個人的基本信息,并返回一個Person類對象。值得注意的是,這里返回的Person類。由于是以引用和遠程調用的方式。這里所傳遞的Person則是以傳值的方式來完成。因此必須涉及到一個序列化的問題。
所以,Remoting要求對象類還要調用或傳遞某個對象,例如類,或者結構,則該類或結構則必須實現串行化Attribute。[Serializable]。






























這個服務器對象,以類庫的方式編譯成Dll,這個工作就算完成了。
那么這個對象是怎么實現被客戶端和服務器端調用的呢?這就是下面我們必須要做的工作:將編譯后的DLL分別添加到服務器端和客戶端程序的引用中。也就是說,這個服務器對象Dll要拷貝兩份,一份放在服務器端,一份放在客戶端。為什么要這樣?看了后面的代碼就知道原因了。
如此一來,會有個問題存在。那就是代碼的安全性。如果客戶端必須要保持這個對象的Dll,則該對象的實現方式對于客戶而言就近乎透明了。另外,這樣對于部署也不好。兩份同樣的dll,如果傳遞的對象大,也會影響性能的。對于這個問題,我們可以使用接口來解決。顯然,服務器端提供接口和具體類的實現,而客戶端則只需要接口就可以了(不過,對于客戶端激活模式則必須有實現接口的類)。






要注意的是:1、兩邊生成該對象程序集的名字必須相同,嚴格地說,是命名空間的名字必須相同。
2、這種方式根據激活方式的不同,實現也不同。如果是服務器端激活(SingleTon和SingCall),那很簡單。如上所述的方法即可;
如果是客戶端激活,最好是利用抽象工廠,提供創建實例的方法。下面的類圖表描述了總體解決方案(MSDN)。
圖 1: 混合法的結構
這樣就必須在代碼中還要加上抽象工廠的接口及實現:












但是由于客戶端激活的方式,它必須調用類的構造函數來創建實例,因此,在客戶端只實現接口似乎是不可能的。
說明:關于對象類繼承MarshalByRefObject,我作過測試,使可以間接地繼承的。也就是我們可以先通過實現基類來繼承它。然后實際所傳遞的對象在從基類中派生。
最后的代碼應該是這樣(服務器端,如果是客戶端,只需要接口即可。這里我加了抽象工廠,因此該對象應該是以客戶端激活模式。如果是服務器端激活模式,應該把抽象工廠接口和實現方法去掉)



































































要補充說明的是,這里傳遞的對象顯然比Socket更多,它甚至可以傳遞DataSet對象。其實,我們可以將它理解為WebService。
二、服務器端監聽程序
寫到這里,我想先介紹一下遠程對象的三種激活模式。激活模式分為兩大類:服務器端激活和客戶端激活。其中服務器端激活又分為:SingleTon和SingleCall兩種。
1、服務器端激活,又叫做WellKnow方式。我不想從理論上來講述,而只是按照自己的理解來解釋。簡單地說,SingleTon激活方式,是對所有用戶都建立一個對象實例,不管這些用戶是在同一客戶端還是不同客戶端。而SingleCall則是對客戶端的每個用戶都建立一個遠程對象實例。至于對象實例的銷毀則是由GC自動管理的。舉例來說,如果遠程對象的一個累加方法(i=0;++i)被多個客戶端(例如兩個)調用。如果是SingleTon方式,則第一個客戶獲得值為1,第二個客戶獲得值為2,因為他們獲得的對象實例是同樣的。而SingleCall方式,則兩個客戶獲得的都是1。原因不言自明。
2、客戶端激活。則是對每個客戶端都建立一個實例。粗看起來和SingleCall相同。實際上是由區別的。首先,對象實例創建的時間不一樣。客戶端激活方式是客戶一旦發出調用的請求,就實例化;而SingleCall則是要等到調用對象方法時在創建。其次,WellKnow方式對對象的管理是由GC管理的,而客戶端則可以自定義生命周期,管理他的銷毀。其三,WellKnow對象是無狀態的,客戶端激活對象則是有狀態的。當然具體到使用上來說,實現的方式也就不一樣了。
好了,現在我們就開始創建服務器端監聽程序。
Remoting傳遞遠程對象實質上來說還是通過Socket來傳遞,因此必須有一個傳遞對象的通道(Channel)。一個通道必須提供一個端口。在Remoting中,通道是由IChannel接口提供。它分別有兩種類型:TcpChannel和HttpChannel。Tcp是以二進制的方式來傳遞,Http則是以Soap的方式來傳遞。兩種通道各有優勢,從性能上看,Tcp更好。但Http可以更好地通過防火墻。因此用戶可以根據自己情況選擇使用通道的方式。(本文使用TcpChannel,事實上兩種可以混合使用,現創建TcpChannel,如果連接失敗,在創建HttpChannel。)通道實現的類為同名類,命名空間則是在System.Runtime.Remoting.Channel下。通過通道可以傳遞對象,而且可以一次傳遞多個對象。對象的傳遞和選擇激活方式,是通過RemotingConfiguratin的靜態方法RegisterWellKnownServiceType()(針對服務器激活模式)和RegisterActivedServiceType()(針對客戶端激活模式)來實現的。代碼如下:



































代碼很簡單。我是用控制臺來提供服務的。這里重點說一樣RegisterWellKnownServiceType()方法的參數。第一個參數就是要傳遞對象的類型。第二個參數是自己定義的遠程對象服務名,其實它是作為客戶端的Uri的一部分。第三個參數自然是定義激活的方式。WellKnownObjectMode是一個枚舉,有SingleCall和SingleTon兩個。
如果是客戶端激活模式,稍有不同:



幾點說明:
1、Dll的引用。要添加第一步所創建的遠程對象Dll;添加System.Runtime.Remoting的引用。
2、關于一個通道傳遞幾個對象。其實沒什么復雜的,再接著用RegiseterWellKnownServiceType()方法就是了。只要這個對象符合我前面所講的要求,同時添加了引用。當然客戶端也要增加相應的代碼。
3、關于多個通道的使用。在Remoting中,可以同時使用多個通道。但要求通道名必須不同。默認建立的TcpChannel名字為Tcp,HttpChannel名字為Http。如果再要建立一個TcpChannel,則必須自己定義一個名字。Channel本身提供ChannelName字段,但該字段是只讀的。所以方法有點變化,要使用HashTable和IDictionary(要添加System.Collection命名空間):





<
發表評論
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元

評論