麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

Microsoft .NET Remoting:技術(shù)概述

2019-11-17 04:51:28
字體:
供稿:網(wǎng)友
  摘要:本文提供了 Microsoft .NET Remoting 框架的技術(shù)概述,其中包括了使用 TCP 通道或 HTTP 通道的示例。

  簡介

  Microsoft? .NET Remoting 提供了一種答應(yīng)對象通過應(yīng)用程序域與另一對象進(jìn)行交互的框架。這種框架提供了多種服務(wù),包括激活和生存期支持,以及負(fù)責(zé)與遠(yuǎn)程應(yīng)用程序進(jìn)行消息傳輸?shù)耐ㄓ嵧ǖ馈8袷交绦蛴糜谠谙⑼ㄟ^通道傳輸之前,對其進(jìn)行編碼和解碼。應(yīng)用程序可以在注重性能的場合使用二進(jìn)制編碼,在需要與其他遠(yuǎn)程處理框架進(jìn)行交互的場合使用 xml 編碼。在從一個(gè)應(yīng)用程序域向另一個(gè)應(yīng)用程序域傳輸消息時(shí),所有的 XML 編碼都使用 SOAP 協(xié)議。出于安全性方面的考慮,遠(yuǎn)程處理提供了大量掛鉤,使得在消息流通過通道進(jìn)行傳輸之前,安全接收器能夠訪問消息和序列化流。

  通常,假如沒有底層框架的支持,治理遠(yuǎn)程對象的生存期會(huì)非常麻煩。.NET Remoting 提供了許多可供選擇的生存期模型,這些模型分為兩個(gè)類別:

  客戶端激活對象

  服務(wù)器激活對象
客戶端激活對象受基于租用的生存期治理器的控制,這種治理器確保了租用期滿時(shí)對象可被回收。而對于服務(wù)器激活對象,開發(fā)人員則可以選擇“單一調(diào)用”模式或“單一元素”模式。

  遠(yuǎn)程對象

  任何遠(yuǎn)程處理框架的主要目的之一就是要提供必要的基礎(chǔ)結(jié)構(gòu),以便隱藏遠(yuǎn)程對象調(diào)用方法和返回結(jié)果的復(fù)雜性。任何位于調(diào)用方應(yīng)用程序域之外的對象,即使在同一臺計(jì)算機(jī)上執(zhí)行,也會(huì)被認(rèn)為是遠(yuǎn)程對象。在應(yīng)用程序域內(nèi)部,原始數(shù)據(jù)類型按數(shù)值傳遞,而所有的對象按引用傳遞。因?yàn)楸镜貙ο笠脙H在創(chuàng)建對象的應(yīng)用程序域內(nèi)有效,所以它們不能以這種方式傳遞到遠(yuǎn)程方法調(diào)用或從遠(yuǎn)程方法調(diào)用返回。所有必須跨越應(yīng)用程序域的本地對象都必須按數(shù)值來傳遞,并且應(yīng)該用 [serializable] 自定義屬性作標(biāo)記,否則它們必須實(shí)現(xiàn) ISerializable 接口。對象作為參數(shù)傳遞時(shí),框架將該對象序列化并傳輸?shù)侥繕?biāo)應(yīng)用程序域,對象將在該目標(biāo)應(yīng)用程序域中被重新構(gòu)造。無法序列化的本地對象將不能傳遞到其他應(yīng)用程序域中,因而也不能遠(yuǎn)程處理。

  通過從 MarshalByRefObject 導(dǎo)出對象,您可以使任一對象變?yōu)檫h(yuǎn)程對象。當(dāng)某個(gè)客戶端激活一個(gè)遠(yuǎn)程對象時(shí),它將接收到該遠(yuǎn)程對象的代理。對該代理的所有操作都被適當(dāng)?shù)刂匦露ㄏ颍惯h(yuǎn)程處理基礎(chǔ)結(jié)構(gòu)能夠正確截取和轉(zhuǎn)發(fā)調(diào)用。盡管這種重新定向?qū)π阅苡幸恍┯绊懀?JIT 編譯器和執(zhí)行引擎 (EE) 已經(jīng)優(yōu)化,可以在代理和遠(yuǎn)程對象駐留在同一個(gè)應(yīng)用程序域中時(shí),防止不必要的性能損失。假如代理和遠(yuǎn)程對象不在同一個(gè)應(yīng)用程序域中,則堆棧中的所有方法調(diào)用參數(shù)會(huì)被轉(zhuǎn)換為消息并被傳輸?shù)竭h(yuǎn)程應(yīng)用程序域,這些消息將在該遠(yuǎn)程應(yīng)用程序域中被轉(zhuǎn)換為原來的堆棧幀,同時(shí)該方法調(diào)用也會(huì)被調(diào)用。從方法調(diào)用中返回結(jié)果時(shí)也使用同一過程。
  代理對象

  代理對象是在客戶端激活遠(yuǎn)程對象時(shí)創(chuàng)建的。作為遠(yuǎn)程對象的代表,代理對象確保對代理進(jìn)行的所有調(diào)用都能夠轉(zhuǎn)發(fā)到正確的遠(yuǎn)程對象實(shí)例。為了準(zhǔn)確理解代理對象的工作方式,我們需要更深入地研究它們。當(dāng)某個(gè)客戶端激活一個(gè)遠(yuǎn)程對象時(shí),框架將創(chuàng)建 TransparentPRoxy 類的一個(gè)本地實(shí)例(該類中包含所有類的列表與遠(yuǎn)程對象的接口方法)。因?yàn)?TransparentProxy 類在創(chuàng)建時(shí)用 CLR 注冊,所以代理上的所有方法調(diào)用都被運(yùn)行時(shí)截取。這時(shí)系統(tǒng)將檢查調(diào)用,以確定其是否為遠(yuǎn)程對象的有效調(diào)用,以及遠(yuǎn)程對象的實(shí)例是否與代理位于同一應(yīng)用程序域中。假如對象在同一個(gè)應(yīng)用程序域中,則簡單方法調(diào)用將被路由到實(shí)際對象;假如對象位于不同的應(yīng)用程序域中,將通過調(diào)用堆棧中的調(diào)用參數(shù)的 Invoke 方法將其打包到 IMessage 對象并轉(zhuǎn)發(fā)到 RealProxy 類中。此類(或其內(nèi)部實(shí)現(xiàn))負(fù)責(zé)向遠(yuǎn)程對象轉(zhuǎn)發(fā)消息。TransparentProxy 類和 RealProxy 類都是在遠(yuǎn)程對象被激活后在后臺創(chuàng)建的,但只有 TransparentProxy 返回到客戶端。

  要更好地理解這些代理對象,我們需要簡要介紹一下 ObjRef。激活一節(jié)中有關(guān)于 ObjRef 的具體說明。以下方案簡要說明了 ObjRef 與這兩個(gè)代理類的關(guān)聯(lián)方式。但請注重,這只是關(guān)于該進(jìn)程的一個(gè)極其概括的說明;根據(jù)對象是客戶端激活對象還是服務(wù)器激活對象,以及它們是單一元素對象還是單一調(diào)用對象,該進(jìn)程會(huì)有所不同。

  遠(yuǎn)程對象注冊在遠(yuǎn)程計(jì)算機(jī)的應(yīng)用程序域中。遠(yuǎn)程對象被封送以生成 ObjRef。ObjRef 包含了從網(wǎng)絡(luò)上的任意位置定位和訪問遠(yuǎn)程對象所需的所有信息,包括:類的增強(qiáng)名稱、類的層次結(jié)構(gòu)(其父類)、類實(shí)現(xiàn)的所有接口的名稱、對象 URI 和所有已注冊的可用通道的具體信息。在接收到對某個(gè)遠(yuǎn)程對象的請求時(shí),遠(yuǎn)程處理框架使用對象 URI 來檢索為該對象創(chuàng)建的 ObjRef 實(shí)例。

  客戶端通過調(diào)用 new 或某個(gè) Activator 函數(shù)(例如 CreateInstance)來激活遠(yuǎn)程對象。對于服務(wù)器激活對象,遠(yuǎn)程對象的 TransparentProxy 將在客戶端應(yīng)用程序域中生成并返回到客戶端,這時(shí)不執(zhí)行任何遠(yuǎn)程調(diào)用。只有在客戶端調(diào)用遠(yuǎn)程對象的某個(gè)方法時(shí),該遠(yuǎn)程對象才會(huì)被激活。此方案明顯不適合客戶端激活對象,因?yàn)榭蛻舳讼M蚣苤辉诘玫秸埱髸r(shí)才激活對象。當(dāng)客戶端調(diào)用某個(gè)激活方法時(shí),客戶端上會(huì)創(chuàng)建一個(gè)激活代理,并且將使用 URL 和對象 URI 作為終結(jié)點(diǎn)在服務(wù)器的遠(yuǎn)程激活器上初始化一個(gè)遠(yuǎn)程調(diào)用。遠(yuǎn)程激活器激活該對象,然后 ObjRef 流向客戶端,并被取消封送以生成一個(gè)返回給客戶端的 TransparentProxy。

  取消封送的過程中會(huì)分析 ObjRef 以提取遠(yuǎn)程對象的方法信息,同時(shí)還會(huì)創(chuàng)建 TransparentProxy 和 RealProxy 對象。在用 CLR 注冊 TransparentProxy 之前,分析后的 ObjRef 內(nèi)容會(huì)被添加到 TransparentProxy 的內(nèi)部表中。

  TransparentProxy 是一種無法替代和擴(kuò)展的內(nèi)部類,而 RealProxy 和 ObjRef 類則屬于公共類,可以在必要時(shí)進(jìn)行擴(kuò)展和自定義。因?yàn)?RealProxy 類能夠處理遠(yuǎn)程對象的所有函數(shù)調(diào)用,所以它是執(zhí)行負(fù)載平衡等操作的理想方法。調(diào)用 Invoke 時(shí),從 RealProxy 導(dǎo)出的類可以獲得網(wǎng)絡(luò)中服務(wù)器的負(fù)載信息,并將該調(diào)用路由到適當(dāng)?shù)姆?wù)器。簡單地為所需的 ObjectURI 從通道請求一個(gè) MessageSink,并調(diào)用 SyncProcessMessage 或 AsyncProcessMessage 以將該調(diào)用轉(zhuǎn)發(fā)至所需的遠(yuǎn)程對象。當(dāng)調(diào)用返回時(shí),通過調(diào)用 RemotingServices 類的 PropagateMessageToProxy 將返回參數(shù)推回到堆棧中。

  下面的代碼片斷顯示了如何使用導(dǎo)出的 RealProxy 類。

MyRealProxy proxy = new MyRealProxy(typeof(Foo));
Foo obj = (Foo)proxy.GetTransparentProxy();
int result = obj.CallSomeMethod();
  上例中獲取的 TransparentProxy 可以被轉(zhuǎn)發(fā)到另一個(gè)應(yīng)用程序域中。當(dāng)?shù)诙€(gè)客戶端試圖調(diào)用代理上的某個(gè)方法時(shí),遠(yuǎn)程處理框架會(huì)嘗試創(chuàng)建 MyRealProxy 類的實(shí)例,并且假如程序集可用,所有的調(diào)用都會(huì)路由至此實(shí)例。假如程序集不可用,調(diào)用會(huì)路由至默認(rèn)的遠(yuǎn)程 RealProxy。

  通過為默認(rèn)的 ObjRef 屬性 TypeInfo、EnvoyInfo 和 ChannelInfo 提供替代,可以很輕易地自定義 ObjRef。下列代碼顯示了如何進(jìn)行自定義:

public class ObjRef {
public virtual IRemotingTypeInfo TypeInfo
{
get { return typeInfo;}
set { typeInfo = value;}
}

public virtual IEnvoyInfo EnvoyInfo
{
get { return envoyInfo;}
set { envoyInfo = value;}
}

public virtual IChannelInfo ChannelInfo
{
get { return channelInfo;}
set { channelInfo = value;}
}
}
  通道

  通道用于在遠(yuǎn)程對象之間傳輸消息。當(dāng)客戶端調(diào)用某個(gè)遠(yuǎn)程對象上的方法時(shí),與該調(diào)用相關(guān)的參數(shù)以及其他具體信息會(huì)通過通道傳輸?shù)竭h(yuǎn)程對象。調(diào)用的任何結(jié)果都會(huì)以同樣的方式返回給客戶端。客戶端可以選擇“服務(wù)器”中注冊的任一通道,以實(shí)現(xiàn)與遠(yuǎn)程對象之間的通訊,因此開發(fā)人員可以自由選擇最適合需要的通道。當(dāng)然,也可以自定義任何現(xiàn)有的通道或創(chuàng)建使用其他通訊協(xié)議的新通道。通道選擇遵循以下規(guī)則:

  在能夠調(diào)用遠(yuǎn)程對象之前,遠(yuǎn)程處理框架必須至少注冊一個(gè)通道。通道注冊必須在對象注冊之前進(jìn)行。

  通道按應(yīng)用程序域注冊。一個(gè)進(jìn)程中可以有多個(gè)應(yīng)用程序域。當(dāng)進(jìn)程結(jié)束時(shí),該進(jìn)程注冊的所有通道將被自動(dòng)清除。

  多次注冊偵聽同一端口的通道是非法的。即使通道按應(yīng)用程序域注冊,同一計(jì)算機(jī)上的不同應(yīng)用程序域也不能注冊偵聽同一端口的通道。

  客戶端可以使用任何已注冊的通道與遠(yuǎn)程對象通訊。當(dāng)客戶端試圖連接至某個(gè)遠(yuǎn)程對象時(shí),遠(yuǎn)程處理框架會(huì)確保該對象連接至正確的通道。客戶端負(fù)責(zé)在嘗試與遠(yuǎn)程對象通訊之前調(diào)用 ChannelService 類的 RegisterChannel。

  所有的通道都由 IChannel 導(dǎo)出,并根據(jù)通道的用途實(shí)現(xiàn) IChannelReceiver 或 IchannelSender。大多數(shù)通道既實(shí)現(xiàn)了接收器接口,又實(shí)現(xiàn)了發(fā)送器接口,使它們可以在兩個(gè)方向上通訊。當(dāng)客戶端調(diào)用代理上的某個(gè)方法時(shí),遠(yuǎn)程處理框架會(huì)截取該調(diào)用并將其轉(zhuǎn)為要發(fā)送到 RealProxy 類(或一個(gè)實(shí)現(xiàn) RealProxy 類的實(shí)例)的消息。RealProxy 將消息轉(zhuǎn)發(fā)到消息接收器以進(jìn)行處理。消息接收器負(fù)責(zé)與遠(yuǎn)程對象注冊的通道之間建立連接,并通過通道(在不同的應(yīng)用程序域)將消息從調(diào)度位置傳輸?shù)竭h(yuǎn)程對象本身。激活了一個(gè)遠(yuǎn)程對象后,客戶端會(huì)通過調(diào)用選定通道上的 CreateMessageSink 來選擇通道,并從其上檢索能夠與遠(yuǎn)程對象通訊的消息接收器。

  遠(yuǎn)程處理框架的一個(gè)輕易混淆的方面是遠(yuǎn)程對象和通道之間的關(guān)系。例如,假如 SingleCall 遠(yuǎn)程對象只在被調(diào)用時(shí)才激活,那么該對象如何偵聽要連接的客戶端?

  部分答案在于這樣一個(gè)事實(shí):遠(yuǎn)程對象并不擁有自己的通道,而是共享通道。作為遠(yuǎn)程對象宿主的服務(wù)器應(yīng)用程序必須注冊要通過遠(yuǎn)程處理框架公開的對象以及所需的通道。注冊后的通道會(huì)自動(dòng)開始在指定的端口偵聽客戶請求。注冊遠(yuǎn)程對象后,會(huì)為該對象創(chuàng)建一個(gè) ObjRef 并將其存儲(chǔ)在表中。當(dāng)通道上傳來一個(gè)請求時(shí),遠(yuǎn)程處理框架會(huì)檢查該消息以確定目標(biāo)對象,同時(shí)檢查對象引用表以定位表中的引用。假如找到了對象引用,將從表中檢索框架目標(biāo)對象或在必要時(shí)將其激活,然后框架將調(diào)用轉(zhuǎn)發(fā)至該對象。對于同步調(diào)用,在消息調(diào)用期間會(huì)一直維持來自客戶端的連接。因?yàn)槊總€(gè)客戶端連接都在自己的線程上處理,所以一個(gè)通道可以同時(shí)服務(wù)于多個(gè)客戶端。

  生成商務(wù)應(yīng)用時(shí),安全性是一個(gè)重要問題。要滿足商務(wù)要求,開發(fā)人員必須能給遠(yuǎn)程方法調(diào)用添加諸如授權(quán)或加密等安全特性。為了實(shí)現(xiàn)這一目標(biāo),開發(fā)人員可以自定義通道,使其能夠?qū)εc遠(yuǎn)程對象之間的實(shí)際消息傳輸機(jī)制進(jìn)行控制。在傳輸?shù)竭h(yuǎn)程應(yīng)用程序之前,所有的消息都必須流過 SecuritySink、TransportSink 和 FormatterSink,且這些消息傳遞到遠(yuǎn)程應(yīng)用程序后會(huì)以相反次序流過同樣的接收器。
  HTTP 通道

  HTTP 通道使用 SOAP 協(xié)議與遠(yuǎn)程對象傳輸消息。所有的消息流過 SOAP 格式化程序時(shí)都被轉(zhuǎn)換為 XML 格式且被序列化,所需的 SOAP 頭也會(huì)被添加到該流中。您也可以指定能夠生成二進(jìn)制數(shù)據(jù)流的二進(jìn)制格式化程序。然后,數(shù)據(jù)流會(huì)使用 HTTP 協(xié)議傳輸?shù)侥繕?biāo) URI。

  TCP 通道

  TCP 通道使用二進(jìn)制格式化程序?qū)⑺械南⑿蛄谢癁槎M(jìn)制流,并使用 TCP 協(xié)議將其傳輸?shù)侥繕?biāo) URI。

  激活

  遠(yuǎn)程處理框架支持遠(yuǎn)程對象的服務(wù)器激活和客戶端激活。不需要遠(yuǎn)程對象在方法調(diào)用之間維護(hù)任何狀態(tài)時(shí),一般使用服務(wù)器激活。服務(wù)器激活也適用于多個(gè)客戶端調(diào)用方法位于同一對象實(shí)例上、且對象在函數(shù)調(diào)用之間維持狀態(tài)的情況。另一方面,客戶端激活對象從客戶端實(shí)例化,并且客戶端通過使用基于租用的專用系統(tǒng)來治理遠(yuǎn)程對象的生存期。

  在可以接受客戶端的訪問之前,所有的遠(yuǎn)程對象都必須用遠(yuǎn)程處理框架注冊。對象注冊一般由宿主應(yīng)用程序來完成。宿主應(yīng)用程序?qū)?dòng),使用 ChannelServices 注冊一個(gè)或多個(gè)通道,使用 RemotingServices 注冊一個(gè)或多個(gè)遠(yuǎn)程對象,然后等待被終止。請注重,已注冊的通道和對象只有在用來注冊它們的進(jìn)程活動(dòng)時(shí)才可以使用。假如退出了該進(jìn)程,則會(huì)自動(dòng)從遠(yuǎn)程處理服務(wù)中刪除它注冊的所有通道和對象。在框架中注冊遠(yuǎn)程對象時(shí),需要以下四項(xiàng)信息:

   包含類的程序集名稱。


   遠(yuǎn)程對象的類型名稱。


   客戶端定位對象時(shí)將使用的對象 URI。


  服務(wù)器激活所需的對象模式。該模式可以是 SingleCall,也可以是 Singleton。
遠(yuǎn)程對象可以通過下列兩種方式注冊:調(diào)用 RegisterWellKnownType,將上述信息作為參數(shù)傳遞;或?qū)⑸鲜鲂畔⒋鎯?chǔ)在配置文件中,然后調(diào)用 ConfigureRemoting 并將該配置文件的名稱作為參數(shù)傳遞。以上兩種方法執(zhí)行的功能相同,因此您可以使用它們中的任意一種來注冊遠(yuǎn)程對象。當(dāng)然,后一種方法更方便些,因?yàn)闊o需重新編譯宿主應(yīng)用程序即可改變配置文件的內(nèi)容。以下代碼片斷顯示了如何將 HelloService 類注冊為 SingleCall 遠(yuǎn)程對象。

RemotingServices.RegisterWellKnownType(
"server",
"Samples.HelloServer",
"SayHello",
WellKnownObjectMode.SingleCall);
  其中,“server”是程序集的名稱,HelloServer 是類的名稱,SayHello 是對象 URI。

  注冊了遠(yuǎn)程對象后,框架將為該對象創(chuàng)建一個(gè)對象引用,然后從程序集中提取與該對象相關(guān)的必要元數(shù)據(jù)。隨后,這一信息將與 URI 和程序集名稱一起存儲(chǔ)在對象引用中(該對象引用將被寫入一個(gè)用于跟蹤已注冊遠(yuǎn)程對象的遠(yuǎn)程處理框架表中)。請注重,除了在客戶端試圖調(diào)用對象上的某個(gè)方法或從客戶端激活對象時(shí)以外,注冊進(jìn)程不會(huì)實(shí)例化遠(yuǎn)程對象自身。

  現(xiàn)在,任何知道該對象 URI 的客戶端都可以使用 ChannelServices 注冊通道,并調(diào)用 new、GetObject 或 CreateInstance 激活對象,從而獲得該對象的一個(gè)代理。以下代碼片斷顯示了該操作的示例:

ChannelServices.RegisterChannel(new TCPChannel);
HelloServer obj = (HelloServer)Activator.GetObject(
typeof(Samples.HelloServer), "tcp://localhost:8085/SayHello");
  其中,“tcp://localhost:8085/SayHello”表示我們希望在端口 8085 上使用 TCP 協(xié)議連接到位于 SayHello 終結(jié)點(diǎn)的遠(yuǎn)程對象。在編譯該客戶端代碼時(shí),編譯器明顯會(huì)要求關(guān)于 HelloServer 類的類型信息。該信息可以通過以下方式之一來提供:

   提供對 HelloService 類所在程序集的引用。

   將遠(yuǎn)程對象拆分為實(shí)現(xiàn)和接口類,并在編譯客戶端時(shí)引用這些接口。

  使用 SOAPSUDS 工具直接從終結(jié)點(diǎn)提取所需的元數(shù)據(jù)。此工具將連接至所提供的終結(jié)點(diǎn),提取元數(shù)據(jù),然后生成可用于編譯客戶端的程序集或源代碼。

  GetObject 或 new 可用于服務(wù)器激活對象。請注重,使用這兩個(gè)調(diào)用時(shí)不會(huì)實(shí)例化對象,實(shí)際上不會(huì)生成任何網(wǎng)絡(luò)調(diào)用。框架從元數(shù)據(jù)獲得了創(chuàng)建代理所需的足夠信息,但并未連接到遠(yuǎn)程對象上。只有在客戶端調(diào)用代理上的某個(gè)方法時(shí)才會(huì)建立網(wǎng)絡(luò)連接。當(dāng)調(diào)用抵達(dá)服務(wù)器時(shí),框架將從消息中提取 URI,檢查遠(yuǎn)程處理框架表以便定位與 URI 匹配的對象引用,然后在必要時(shí)將對象實(shí)例化,并將方法調(diào)用轉(zhuǎn)發(fā)至對象。假如將對象注冊為 SingleCall,則完成方法調(diào)用后該對象會(huì)取消。每次調(diào)用一個(gè)方法時(shí),都會(huì)創(chuàng)建一個(gè)新的實(shí)例。GetObject 和 new 之間的唯一差別在于,前者答應(yīng)指定 URL 作為參數(shù),而后者從配置中獲得 URL。

  CreateInstance 或 new 可用于客戶端激活對象。兩者都答應(yīng)使用帶參數(shù)的構(gòu)造函數(shù)來實(shí)例化對象。客戶端激活對象的生存期由遠(yuǎn)程處理框架提供的租用服務(wù)控制。對象租用的內(nèi)容在下一節(jié)中說明。
更多的請看:http://www.QQread.com/windows/2003/index.Html
  對象的租用生存期

  每個(gè)應(yīng)用程序域都包含一個(gè)用于治理其租用情況的租用治理器。所有的租用都會(huì)被定期檢查,以確定租用是否已過期。假如租用過期,則會(huì)調(diào)用該租用的一個(gè)或多個(gè)發(fā)起者,使它們有機(jī)會(huì)更新租用。假如所有的發(fā)起者都不預(yù)備更新租用,則租用治理器會(huì)刪除該租用并將該對象作為垃圾回收。租用治理器按照剩余租用時(shí)間的順序維護(hù)租用列表。剩余時(shí)間最短的租用排在列表的頂端。

  租用可以實(shí)現(xiàn) ILease 接口并存儲(chǔ)一個(gè)屬性集合,用于確定更新的策略和方法。您也可以使用調(diào)用來更新租用。每次調(diào)用遠(yuǎn)程對象上的方法時(shí),租用時(shí)間都會(huì)設(shè)置為目前 LeaseTime 最大值加上 RenewOnCallTime。LeaseTime 即將過期時(shí),發(fā)起者會(huì)被要求更新租用。因?yàn)槲覀冇袝r(shí)會(huì)遇上網(wǎng)絡(luò)不穩(wěn)定,所以可能會(huì)找不到租用發(fā)起者。為了確保不在服務(wù)器上留下無效對象,每個(gè)租用都帶有一個(gè) SponsorshipTimeout。該值指定了租用終止之前等待租用發(fā)起者回復(fù)的時(shí)間長度。假如 SponsershipTimeout 為零,CurrentLeaseTime 會(huì)被用于確定租用的過期時(shí)間。假如 CurrentLeaseTime 的值為零,則租用不會(huì)過期。配置或 API 可用于替代 InitialLeaseTime、SponsorshipTimeout 和 RenewOnCallTime 的默認(rèn)值。

  租用治理器維護(hù)著一個(gè)按發(fā)起時(shí)間從大到小存儲(chǔ)的發(fā)起者列表(它們實(shí)現(xiàn) ISponsor 接口)。需要調(diào)用發(fā)起者以更新租用時(shí)間時(shí),租用治理器會(huì)從列表的頂部開始向一個(gè)或多個(gè)發(fā)起者要求更新租用時(shí)間。列表頂部的發(fā)起者表示其以前請求的租用更新時(shí)間最長。假如發(fā)起者沒有在 SponsorshipTimeOut 時(shí)間段內(nèi)響應(yīng),則它會(huì)被從列表中刪除。通過調(diào)用 GetLifetimeService 并將對象租用作為參數(shù),即可以獲得該對象租用。該調(diào)用是 RemotingServices 類的一個(gè)靜態(tài)方法。假如對象在應(yīng)用程序域內(nèi)部,則該調(diào)用的參數(shù)是對象的本地引用,且返回的租用也是該租用的本地引用。假如對象是遠(yuǎn)程的,則代理會(huì)作為一個(gè)參數(shù)傳遞,且返回給調(diào)用方的是租用的透明代理。

  對象能夠提供自己的租用并控制自己的生存期。它們通過替代 MarshalByRefObject 上的 InitializeLifetimeService 方法來完成該操作,如下所示:

public class Foo : MarshalByRefObject {
public override Object InitializeLifetimeService()
{
ILease lease = (ILease)base.InitializeLifetimeService();
if (lease.CurrentState == LeaseState.Initial) {
lease.InitialLeaseTime = TimeSpan.FromMinutes(1);
lease.SponsorshipTimeout = TimeSpan.FromMinutes(2);
lease.RenewOnCallTime = TimeSpan.FromSeconds(2);
}
return lease;
}
}
  只有當(dāng)租用處于初始狀態(tài)時(shí),才可以更改租用屬性。InitializeLifetimeService 的實(shí)現(xiàn)通常調(diào)用基類的相應(yīng)方法,來檢索遠(yuǎn)程對象的現(xiàn)有租用。假如在此之前從未對該對象封送過,則返回的租用會(huì)處于其初始狀態(tài)且可以設(shè)置租用屬性。一旦封送了對象,則租用會(huì)從初始狀態(tài)變?yōu)榧せ顮顟B(tài),并忽略任何初始化租用屬性的嘗試(但有一種情況例外)。激活遠(yuǎn)程對象時(shí)將調(diào)用 InitializeLifetimeService。通過激活調(diào)用可以提供一個(gè)租用發(fā)起者的列表,而且當(dāng)租用處于激活狀態(tài)時(shí),可以隨時(shí)將其他發(fā)起者添加到列表中。

  可以下列方式延長租用時(shí)間:

   客戶端可以調(diào)用 Lease 類上的 Renew 方法。

   租用可以向某個(gè)發(fā)起者請求 Renewal。

  當(dāng)客戶端調(diào)用對象上的某個(gè)方法時(shí),RenewOnCall 值會(huì)自動(dòng)更新租用。
一旦租用過期,其內(nèi)部狀態(tài)會(huì)由 Active 變?yōu)?EXPired,且不再對發(fā)起者進(jìn)行任何調(diào)用,對象也會(huì)被作為垃圾回收。一般情況下,假如發(fā)起者分散在 Web 上或位于某個(gè)防火墻的后面,遠(yuǎn)程對象回叫發(fā)起者時(shí)會(huì)碰到困難。因此,發(fā)起者不必與客戶端處于同一位置,只要遠(yuǎn)程對象能夠訪問得到,它可以為網(wǎng)絡(luò)上的任意位置。

  通過租用來治理遠(yuǎn)程對象的生存期可以作為引用計(jì)數(shù)的一種替代方法,因?yàn)楫?dāng)網(wǎng)絡(luò)連接的性能不可靠時(shí),引用計(jì)數(shù)會(huì)顯得復(fù)雜和低效。盡管有人會(huì)堅(jiān)持認(rèn)為遠(yuǎn)程對象的生存期比所需的時(shí)間要長,但與引用計(jì)數(shù)和連接客戶相比,租用降低了網(wǎng)絡(luò)的繁忙程度,將會(huì)成為一種非常受歡迎的解決方案。

  總結(jié)

  要提供完美的、能夠滿足大多數(shù)商務(wù)應(yīng)用需求的遠(yuǎn)程處理框架,即使能夠做到,也必然會(huì)非常困難。Microsoft 提供了能夠根據(jù)需要進(jìn)行擴(kuò)展和自定義的框架,在正確的方向上邁出了要害的一步。更多的請看:http://www.qqread.com/windows/2003/index.html
  附錄 A:使用 TCP 通道進(jìn)行遠(yuǎn)程處理的示例

  此附錄顯示了如何編寫簡單的“Hello World”遠(yuǎn)程應(yīng)用程序。客戶端將一個(gè)字符串傳遞到遠(yuǎn)程對象上,該遠(yuǎn)程對象將單詞“Hi There”附加到字符串上,并將結(jié)果返回到客戶端。

  將此文件保存為 server.cs。此處為服務(wù)器的代碼:

using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels.TCP;

namespace RemotingSamples {
public class HelloServer : IHello {

public static int Main(string [] args) {

TCPChannel chan = new TCPChannel(8085);
ChannelServices.RegisterChannel(chan);
RemotingServices.RegisterWellKnownType(
"server", "RemotingSamples.HelloServer", "SayHello", WellKnownObjectMode.SingleCall);
System.Console.WriteLine("請按 鍵退出...");
System.Console.ReadLine();
return 0;
}

public HelloServer()
{
Console.WriteLine("HelloServer 已激活");
}

~HelloServer()
{
Console.WriteLine("對象已清除");
}

public ForwardMe HelloMethod(ForwardMe obj)
{
Console.WriteLine("Hello.HelloMethod : {0}", name);
return "Hi there " + name;
}
}
}

將此代碼保存為 client.cs:

using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels.TCP;

namespace RemotingSamples {
public class Client
{
public static int Main(string [] args)
{
TCPChannel chan = new TCPChannel();
ChannelServices.RegisterChannel(chan);
ForwardMe param = new ForwardMe();
HelloServer obj = (HelloServer)Activator.GetObject(
typeof(RemotingSamples.HelloServer), "tcp://localhost:8085/SayHello");
if (obj == null) System.Console.WriteLine("無法定位服務(wù)器");
else {
Console.WriteLine("值為 " + param.getValue());
ForwardMe after = obj.HelloMethod(param);
Console.WriteLine("呼叫后的值為 " + after.getValue());
}
return 0;
}
}
}
下面是 makefile:

all: server.exe client.exe share.dll

share.dll: share.cs
csc /debug+ /target:library /out:share.dll share.cs

server.exe: server.cs
csc /debug+ /r:share.dll /r:System.Runtime.Remoting.dll server.cs

client.exe: client.cs server.exe
csc /debug+ /r:share.dll /r:server.exe /r:System.Runtime.Remoting.dll client.cs

clean:
@del server.exe client.exe *.pdb *~ *.*~
更多的請看:http://www.qqread.com/windows/2003/index.html
  附錄 B:使用 HTTP 通道進(jìn)行遠(yuǎn)程處理的示例

  將此文件保存為 server.cs。此處為服務(wù)器的代碼:

using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels.HTTP;

namespace RemotingSamples {
public class HelloServer : IHello {

public static int Main(string [] args) {

HTTPChannel chan = new HTTPChannel(8085);
ChannelServices.RegisterChannel(chan);
RemotingServices.RegisterWellKnownType(
"server", "RemotingSamples.HelloServer", "SayHello", WellKnownObjectMode.SingleCall);
System.Console.WriteLine("請按 鍵退出...");
System.Console.ReadLine();
return 0;
}

public HelloServer()
{
Console.WriteLine("HelloServer 已激活");
}

~HelloServer()
{
Console.WriteLine("對象已清除");
}

public ForwardMe HelloMethod(ForwardMe obj)
{
Console.WriteLine("Hello.HelloMethod : {0}", name);
return "Hi there " + name;
}
}
}
  將此代碼保存為 client.cs:

using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels.HTTP;

namespace RemotingSamples {
public class Client
{
public static int Main(string [] args)
{
HTTPChannel chan = new HTTPChannel();
ChannelServices.RegisterChannel(chan);
ForwardMe param = new ForwardMe();
HelloServer obj = (HelloServer)Activator.GetObject(
typeof(RemotingSamples.HelloServer), "http://localhost:8085/SayHello");
if (obj == null) System.Console.WriteLine("無法定位服務(wù)器");
else {
Console.WriteLine("值為 " + param.getValue());
ForwardMe after = obj.HelloMethod(param);
Console.WriteLine("呼叫后的值為 " + after.getValue());
}
return 0;
}
}
}
  下面是 makefile:

all: server.exe client.exe share.dll

share.dll: share.cs
csc /debug+ /target:library /out:share.dll share.cs

server.exe: server.cs
csc /debug+ /r:share.dll /r:System.Runtime.Remoting.dll server.cs

client.exe: client.cs server.exe
csc /debug+ /r:share.dll /r:server.exe /r:System.Runtime.Remoting.dll client.cs

clean:
@del server.exe client.exe *.pdb *~ *.*~



發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 欧美一级做a | 粉嫩粉嫩一区二区三区在线播放 | 免费一级欧美在线观看视频 | 7777在线视频免费播放 | h视频在线播放 | 日韩专区在线 | 天天艹综合 | 精品中文字幕在线播放 | 久久免费视频一区二区三区 | 少妇色诱麻豆色哟哟 | 国产外围在线 | 青青草成人免费视频在线 | 日本在线观看中文字幕 | 高清中文字幕在线 | 1级黄色毛片| 一级成人免费 | 午夜国产精品成人 | 成人福利视频网站 | 欧美精品一区自拍a毛片在线视频 | 最新中文字幕在线视频 | 国产精品久久久久久久久久10秀 | 欧美日韩免费观看视频 | 91,视频免费看 | 亚洲精品一区二区三区大胸 | 色婷婷久久久 | 夜夜夜精品视频 | 成人免费av在线播放 | 黄网在线 | 午色影院 | 在线播放av网址 | 神马福利电影 | 自拍偷拍亚洲图片 | 欧美.com | 欧美一级淫片免费视频1 | 人成免费a级毛片 | 精品国产乱码久久久久久丨区2区 | 国产精品久久久久久久不卡 | 51国产偷自视频区视频小蝌蚪 | 在线播放亚洲精品 | 性视频久久| 久久综合久久综合久久 |