使用 .NET 遠程處理訪問其他應用程序域中的對象

 

在運行於不同進程中的對象之間建立通訊(無論是在同一臺計算機上,還是在相距數千公里的計算機上)是常見的開發目標,尤其是在生成大範圍分佈式應用程序的時候。傳統上,這需要深入瞭解相關知識:不僅是關於通訊流任一端的對象的知識,而且還有關於低級別協議的主機、應用程序編程接口以及配置工具或文件的知識。簡言之,它是一項需要大量專業知識和經驗的複雜任務。<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

.NET 框架提供了幾種可用來快速而方便地完成此任務的通訊方法,而無論您是否對協議和編碼有大量的瞭解。因此,無論是需要快速開發 Web 應用程序,還是要花費更多時間生成關鍵的企業範圍的應用程序(在此過程中涉及許多計算機或操作系統,並使用多種協議和序列化優化),.NET 框架都會支持您的方案。跨進程通訊仍然是一項複雜的任務,但現在它的許多工作都由 .NET 框架處理。

選擇 .NET 中的通訊選項

.NET 框架提供了幾種與不同應用程序域中的對象進行通訊的方式,每一種方式都具有特定級別的專業性和靈活性。例如,Internet 的發展已經使 XML Web services 成爲一種頗具吸引力的通訊方法,這是因爲 XML Web services 是建立在使用 XML 的 HTTP 協議和 SOAP 格式化的通用基礎結構之上的。這些都是公共標準,並且可以直接與當前的 Web 基礎結構結合使用,而無需擔心其他的代理或防火牆問題。

然而,如果只是存在與在 HTTP 連接上使用 SOAP 序列化相關的性能問題,那麼並不是所有的應用程序都應使用某種形式的 XML Web services 來建立。下面的子節應有助於您確定要爲應用程序採用哪種形式的對象間通訊。

ASP.NET 還是遠程處理?

ASP.NET 和 .NET 遠程處理都是進程間的通訊實現方法。ASP.NET 提供一種由 Internet 信息服務 (IIS) 承載的基礎結構,該結構擅長處理基本類型,而且是 Web 應用程序開發人員所熟悉的。.NET 遠程處理是一般性的且具有高度可擴展性的進程間通訊系統,可以用來創建在 IIS 中承載的 XML Web services(並具有 ASP.NET 和 IIS 的所有安全性、可伸縮性以及會話和應用程序狀態)或任何其他類型的通訊。

所需的通訊類型和您所熟悉的編程模型是您在兩種編程模型之間進行選擇的主要依據。請首先選擇所需的進程間通訊類型,然後選擇能以最容易的方式最佳地實現您的決定的編程模型。以下是選擇您可能需要的進程間通訊類型的一些依據(按優先級排序):

1.     安全需要。如果需要保證調用的安全,則必須使用在 IIS 中承載的基於 HTTP 的應用程序,無論它是 ASP.NET 應用程序還是遠程處理應用程序。在 IIS 中,基於 ASP.NET 和 .NET 遠程處理的應用程序都具有您可能需要的所有安全功能。使用任何其他傳輸協議,或是在 IIS 外使用 HttpChannel,都需要您自己完成安全工作。請注意,在使用 HTTP 連接時無需使用 SOAP 編碼格式;可以使用二進制編碼來提高速度。

2.     速度。如果每個調用的效率很關鍵,則應當使用二進制編碼,即使您不使用默認的 TcpChannel 也如此。在遠程處理中,可以結合使用二進制格式化程序和 HttpChannel;在 ASP.NET 中,可以使用 POST 通訊。單是使用二進制格式化就可以顯著地提高遠程處理中的調用性能,即使您使用的是 HttpChannel 也如此。如果沒有任何安全問題(例如,如果正在生成完全在防火牆內部運行的小應用程序),則使用二進制格式化的默認 TcpChannel 就能夠達到最佳性能。

3.     交互操作。如果必須在不同的操作系統之間進行交互操作,則無論使用 .NET 遠程處理還是使用 ASP.NET,都應當使用 SOAP 格式化協議。

4.     可縮放性。無論使用 .NET 遠程處理還是使用 ASP.NET,將應用程序承載在 IIS 內部都會獲得所需的可縮放性。

5.     隨機變更。有幾種問題可能會與您有關,例如:

·         編程模型易於使用。

·         易於實現擴展性。

·         自定義需要。

·         使用 C++ 的託管擴展。

·         對於遠程對象激活、生存期或用戶權限的特殊需要。

·         是否需要完全的類型保真。

.NET 遠程處理系統爲所有這些要求提供瞭解決方案,而 ASP.NET 系統只對其中某些要求提供支持。

以下是使用 ASP.NET、System.Net 命名空間和 .NET 遠程處理生成的 XML Web services 之間存在的一些差異的簡短摘要。

XML Web services

如果您是生成 ASP 應用程序並希望使用 Web 應用程序模型和 ASP.NET HTTP 運行庫的功能(包括 Microsoft Visual Studio .NET 中的強大支持),則使用 ASP.NET 生成的 Web 服務可以滿足您的要求。通過 XML Web services 基礎結構,可以使用最適合於基於 Web 的應用程序的協議、格式和數據類型來方便地創建自己的組件供其他應用程序使用,或是使用他人創建的組件。它不支持 .NET 計算機之間的完全類型保真,並且僅可以傳遞某些類型的參數。

System.Net 命名空間

可以使用 System.Net 命名空間中的類從無到有生成整個通訊結構。還可以使用 System.Net 類實現您自己的可以插入到遠程處理結構中的通訊協議和序列化格式。

.NET 遠程處理

.NET 遠程處理提供用於實現任意數量的全面通訊方案(包括但不僅限於 XML Web services)的工具。使用 .NET 遠程處理可以:

  • 在任意類型的應用程序域中發佈或使用服務,無論該域是控制檯應用程序、Windows 窗體、Internet 信息服務 (IIS)、XML Web services 還是 Windows 服務。

  • 在二進制格式的通訊中保持完整的託管代碼類型系統保真度。

注意 XML Web services 使用 SOAP 格式化,這種格式化不會保持所有的類型詳細信息。

  • 通過引用傳遞對象並返回到特定應用程序域中的特定對象。

  • 直接控制激活特性和對象生存期。

  • 實現和使用第三方信道或協議來擴展通訊以滿足特定要求。

  • 直接參與通訊進程以創建所需的功能。

.NET 遠程處理概述

可以使用 .NET 遠程處理來使不同的應用程序能夠互相通訊,而無論這些應用程序是駐留在同一臺計算機上、位於同一局域網中的不同計算機上還是位於相隔萬里的差異巨大的網絡中(即使計算機運行不同的操作系統)。

.NET 框架提供多種服務(如激活和生存期控制),以及負責在本地和遠程應用程序之間傳輸消息的通訊信道。格式化程序用於在沿信道發送消息之前對消息進行編碼和解碼。應用程序可以在性能很關鍵時使用二進制編碼,或是在與其他遠程處理系統的互操作性至關重要時使用 XML 編碼。遠程處理的設計考慮到了安全性,因此您可以使用一些掛鉤來訪問調用消息和序列化流,以便在通過信道傳輸它們以前保證它們的安全。

遠程處理基礎結構是進程間通訊的抽象方法。系統的大部分在運行時無需關心。例如,可以通過值傳遞或可以複製的對象是自動在不同應用程序域中的或不同計算機上的應用程序之間傳遞的。只需將自定義類標記爲可序列化便可使它工作。

然而,遠程系統的真正優點在於它具有使位於不同應用程序域或者進程(它們使用不同的傳輸協議、序列化格式、對象生存期方案和對象創建模式)中的對象互相通訊的能力。此外,如果出於任何原因,需要干預通訊進程的幾乎任何階段,遠程處理使這種干預變爲可能。

無論您已經實現了一些分佈式應用程序,還是隻對將組件移動到其他計算機上以增加程序的可伸縮性感興趣,您都可以非常容易地將遠程處理系統理解爲一般性的進程間通訊系統,它具有一些能夠輕鬆處理大多數方案的默認實現。下面的討論從使用遠程處理進行進程間通訊的基礎知識開始。

副本與引用

進程間通訊需要一個向其進程外的調用方提供功能的服務器對象、一個在服務器對象上進行調用的客戶端以及一個將調用從一端運送到另一端的傳輸機制。服務器方法的地址是邏輯地址,並且在一個進程中正常工作,但不能在其他客戶端進程中正常工作。若要解決此問題,客戶端調用服務器對象的一種方法是:創建對象的完整副本並將該副本移動到客戶端進程(在該進程中可以直接調用副本的方法)。

然而,許多對象無法或不應複製和移動到某個其他進程來執行。具有許多方法的非常大的對象不適合複製到或通過值傳遞到其他進程。通常,客戶端僅需要由服務器對象上的一個或幾個方法返回的信息。複製整個服務器對象(包括可能是與客戶端需求無關的大量內部信息或可執行結構)將是對帶寬以及客戶端內存和處理時間的浪費。另外,許多對象公開公共功能,但是需要用於內部執行的私有數據。複製這些對象會使惡意客戶端能夠查看內部數據,從而產生安全問題隱患。最後,某些對象使用的數據乾脆就無法以任何可理解的方式複製。例如,FileInfo 對象包含一個對操作系統文件的引用,此文件在服務器進程的內存中具有唯一的地址。可以複製這個地址,但它在另一進程中將永遠不會具有任何意義。

在這些情況下,服務器進程應當向客戶端進程傳遞一個對服務器對象的引用,而不是傳遞該對象的副本。客戶端可以使用此引用來調用服務器對象。這些調用不在客戶端進程中執行。相反,遠程處理系統收集關於調用的所有信息並將其發送到服務器進程,在該進程中,將解釋這些信息並查找正確的服務器對象,然後代表客戶端對象向該服務器對象發出調用。然後,調用的結果被髮送回客戶端進程以返回到客戶端。帶寬僅用於關鍵信息:調用、調用參數以及任何返回值或異常。

簡化的遠程處理結構

使用對象引用在服務器對象和客戶端之間進行通訊是遠程處理的核心。然而,遠程處理結構向程序員提供了更簡單的過程。如果正確配置了客戶端,只需要使用 new(或託管編程語言中的實例創建函數)創建遠程對象的新實例。客戶端接收對服務器對象的引用,然後就可以像該對象位於您的進程中而不是運行在另外一臺計算機上一樣調用其方法。遠程處理系統使用代理對象來產生服務器對象位於客戶端進程中的效果。代理是將它們自身顯示爲某個其他對象的臨時代理對象。當客戶端創建遠程類型的實例時,遠程處理基礎結構創建對於客戶端來說看起來與遠程類型完全相同的代理對象。客戶端調用此代理上的方法,而遠程處理系統則接收調用,將其路由到服務器進程,調用服務器對象,並將返回值返回到客戶端代理,而客戶端代理將結果返回到客戶端。

遠程調用必須以某種方式在客戶端和服務器進程之間傳送。如果要自己生成遠程處理系統,可以從學習網絡編程、各種各樣的協議和序列化格式規範開始。在 .NET 遠程處理系統中,打開網絡連接和使用特定協議將字節發送到接收應用程序所需的基礎技術的組合被表示爲傳輸信道。

信道是一個承載數據流,根據特定網絡協議創建包並將該包發送到另一臺計算機的類型。某些信道只能接收信息,另外一些只能發送信息,還有一些(例如默認的 TcpChannel 和 HttpChannel 類)可以在兩個方向上使用。

雖然服務器進程瞭解有關每個唯一類型的一切信息,但是客戶端僅知道它需要對其他應用程序域(可能在其他計算機上)中的某個對象的引用。從服務器應用程序域外的世界來說,該對象是通過 URL 查找的。向外部世界表示唯一類型的 URL 是激活 URL,它們確保遠程調用是向正確的類型發出的。

完整的遠程處理系統設計

假定您的應用程序在一臺計算機上運行,而您想使用由存儲在另一臺計算機上的類型公開的功能。下圖顯示常規的遠程處理過程。

遠程處理過程

<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" />

如果關係兩端都是正確配置的,則客戶端僅創建一個服務器類的新實例。遠程處理系統創建一個表示該類的代理對象,並向客戶端對象返回一個對該代理的引用。當客戶端調用方法時,遠程處理基礎結構接應該調用,檢查類型信息,並通過信道將該調用發送到服務器進程。偵聽信道獲得該請求並將其轉發給服務器遠程處理系統,服務器遠程處理系統查找(或在必要時創建)並調用被請求的對象。然後,此過程將反向進行,服務器遠程處理系統將響應捆綁成消息並由服務器信道發送到客戶端信道。最後,客戶端遠程處理系統通過代理將調用的結果返回給客戶端對象。

爲使此過程工作只需要非常少的實際代碼,但應當認真考慮關係的設計和配置。即使代碼完全正確,仍然可能因爲 URL 或端口號不正確而失敗。

雖然遠程處理進程的這種高級別概述相當簡單,但低級別的詳細信息可能是非常複雜的。其他主題中提供了對遠程處理的主要元素的更爲深入的討論,如下面所列出的主題所示。

可遠程處理的和不可遠程處理的對象

請一定記住,在某個應用程序域中創建並因此特定於它的對象可以在此域中直接調用,但在此對象可以在它的域以外使用之前必須進行一些特殊處理。並非每種類型的對象都可以跨域的邊界高效地發佈或使用;因此,必須根據應用程序的需要決定要發佈哪種類型的對象。

根據分佈式應用程序的用途,有兩種簡單的對象類別:可遠程處理的對象和不可遠程處理的對象。不可遠程處理的對象不向系統提供複製它們或在其他應用程序中表示它們的任何方法。因此,這些對象僅可以從它們的原始應用程序域中訪問。可遠程處理的對象既可以使用代理在其應用程序域或上下文外部訪問,也可以複製它們並且可以將這些副本傳遞到它們的應用程序域或上下文外;換句話說,某些可遠程處理的對象通過引用傳遞,而另一些通過值傳遞。

不可遠程處理的對象

某些對象不能離開它們的應用程序域;它們永遠不會被封送處理,原因是它們不聲明序列化方法。這些不可遠程處理的對象專用於創建它們的同一應用程序域內部,並且總是從該同一應用程序域中直接訪問。.NET 框架類庫中的大多數基類是不可遠程處理的對象。

可遠程處理的對象

可遠程處理的對象是能在大範圍的分佈環境中正常運行的對象。有兩種主要的可遠程處理的對象:

  • 按值封送對象,它們被複制並傳出應用程序域。

  • 按引用封送對象,將爲其創建代理,而該代理由客戶端用於遠程訪問對象。

按值封送對象

按值封送 (MBV) 對象聲明它們的序列化規則(通過實現 ISerializable 來實現其自身的序列化,或者通過用 SerializableAttribute 修飾,該屬性通知系統自動序列化該對象),但是不擴展 MarshalByRefObject。遠程處理系統創建這些對象的完整副本並將副本傳遞到進行調用的應用程序域。一旦副本到達調用方的應用程序域內,對它的調用就是對該副本的直接調用。而且,當 MBV 對象作爲參數傳遞時,也是通過值傳遞的。除聲明 SerializableAttribute 或實現 ISerializable 之外,無需做其他任何事情就可以將類的實例跨應用程序或上下文邊界通過值傳遞。

當由於性能或處理原因,將對象的完整狀態和任何可執行功能移動到目標應用程序域有意義時,應當使用 MBV 對象。在許多方案中,這減少了跨網絡、進程和應用程序域邊界的冗長而耗費資源的往返行程。MBV 對象還可以從對象的原始應用程序域內直接使用。在這種情況下,由於不進行任何封送處理,因此不創建任何副本而且訪問非常高效。

另一方面,如果發佈的對象非常大,那麼在繁忙的網絡上傳遞整個副本對於應用程序來說可能不是最佳的選擇。此外,永遠不會將對複製對象的狀態所做的更改傳回到起始應用程序域中的原始對象。在抽象級別上,這種方案類似於客戶端瀏覽器所請求的靜態 HTML 頁的方案。服務器複製文件,將其寫入到流中,發送出去,然後忘掉它。所有後續的請求都只是對其他副本的其他請求。

遠程處理系統廣泛使用可序列化的對象。對其他應用程序域中的對象的引用(由 ObjRef 類在遠程處理系統中表示)本身是可序列化的;必須能夠將它精確地複製並將副本發送給請求。同樣,對於實現 IMessage 的消息對象也是如此,這是因爲它們是調用信息和所有其他所需對象引用的一般容器。另外,僅傳輸數據的對象通常是 MBV 對象。例如,DataSet 擴展實現 ISerializable 的 MarshalByValueComponent。

按引用封送的對象

按引用封送 (MBR) 的對象是至少擴展 System.MarshalByRefObject 的可遠程處理的對象。根據已聲明的激活類型,當客戶端在自己的應用程序域中創建 MBR 對象的實例時,.NET 遠程處理基礎結構在調用方的應用程序域中創建表示該 MBR 對象的代理對象,並向調用方返回對此代理的引用。然後客戶端將在該代理上進行調用;遠程處理封送這些調用,    將它們發送回起始應用程序域,並在實際對象上調用該調用。

注意 如果客戶端位於與 MBR 對象相同的應用程序域中,基礎結構將向客戶端返回對該 MBR 對象的直接引用,從而避免封送處理的系統開銷。

如果 MarshalByRefObject 作爲參數傳入,當調用到達時,它變成另一個應用程序域中的代理。MBR 返回值,並且 out 參數以相同的方式工作。

當對象的狀態和任何可執行的功能應處在創建它的應用程序域中時,應當使用 MBR 對象。例如,具有內部字段且該內部字段是操作系統句柄的對象應擴展 MarshalByRefObject,這是因爲操作系統句柄在其他進程中或其他計算機上的其他應用程序域中是無意義的。有時對象可能大得難以想象;對於功能強大的服務器還行,但通過網絡發送到 33.6 kbps 的調制解調器就不行了。

上下文綁定對象

上下文綁定對象是從 System.ContextBoundObject(它本身從 System.MarshalByRefObject 繼承)繼承的 MBR 對象。可以將上下文當作應用程序域的子部分,它在執行期間爲駐留在其中的對象提供某種資源充足的環境(例如保證對象不會被多個線程同時訪問)。每個應用程序域都具有默認的上下文,大多數託管代碼使用應用程序域的默認上下文創建對象並直接從同一應用程序域內部調用成員,而不會產生與上下文有關的問題。所有從 ContextBoundObject 繼承的類型都作爲代理向其他上下文公開,無論它們是否在同一應用程序域中。

例如,假定有一個某類型上的方法,該類型是事務的一部分因而受到特定於在其中創建它的上下文的規則的約束。應當使該類型從 ContextBoundObject 繼承,這樣就可以從對象本身的上下文訪問該對象,而且系統可以強制實施有關與對象及其方法關聯的事務的規則。如果從同一應用程序域內部的另一上下文中調用 ContextBoundObject,則將爲調用方創建代理,但是上下文間的通訊不通過信道系統,從而在此情況下提高了調用效率。

考慮要遠程處理哪種類別的類型時,請決定需要通過哪些邊界。特定於某個特定上下文的對象只能從該上下文中直接訪問。對於特定於某個特定應用程序域的對象也是如此。若要遠程處理這兩者中的任一種對象,在從服務器對象所特定於的邊界內調用該服務器對象之前,遠程處理系統必須成功通過上下文邊界、應用程序邊界或是成功通過這兩種邊界。由於通過每一邊界都要花費處理時間,因而爲了決定服務器應當是何種類型的可遠程處理對象,就需要確定對象必須通過哪些邊界。如果無需上下文檢查就調用對象,則不應讓遠程類型擴展 ContextBoundObjectMarshalByRefObject 將執行得更好)。如果確實需要上下文檢查,則應當擴展 ContextBoundObject,但是需要明白:在對象上進行調用之前,必須通過附加的邊界。

對象激活和生存期

多數情況下,無需注意創建對象的確切時間;只需在對象上調用方法時讓它作出響應。然而,當生成遠程對象時,必須知道新對象是何時以及如何創建和初始化的,即它是如何激活的。在可以使對象對於客戶端可用之前,遠程處理系統必須總是知道需要哪種類型的激活;因此,理解您的選擇是很重要的。

激活

對於按引用封送 (MBR) 的對象,有兩種激活類型:服務器激活和客戶端激活。

服務器激活的對象:

  • 只在需要它們時由服務器創建——不是在通過調用 new 或 Activator.GetObject() 創建客戶端代理時創建,而是在客戶端調用該代理上的第一個方法時創建。

  • 可以聲明爲 SingletonSingleCall 對象。Singleton 對象是這樣的對象:無論該對象有多少個客戶端,總是隻有一個實例,且該對象具有默認的生存期。將對象聲明爲 SingleCall 對象時,系統爲每個客戶端方法調用創建一個新對象。客戶端可以使用生存期租約系統參與這些實例的生存期。

客戶端激活的對象:

  • 客戶端調用 new 或 Activator.CreateInstance() 時在服務器上創建。使用生存期租約系統,客戶端本身可以參與這些實例的生存期。

生存期租約

按引用封送的對象 (MBR)無論是服務器激活的 Singleton 對象還是客戶端激活的對象,都不會永遠駐留在內存中。相反,除非該類型重寫 MarshalByRefObject.InitializeLifetimeService() 以控制自己的生存期策略,否則每個 MBR 的生存期都是由租約、租約管理器和一些主辦方的組合控制的。(在這種情況下,MBR 對象的生存期是對象在內存中保持活動狀態的總時間。)租約本身是 .NET 遠程處理系統開始刪除某個特定對象並回收內存的進程之前,該特定對象在內存中保持活動狀態的時間。服務器應用程序域的租約管理器是確定何時標記遠程對象以供進行垃圾回收的對象。主辦方是可以通過將其本身註冊到租約管理器來爲特定對象請求新租約的對象。

只要 MBR 對象被在應用程序域外部進行遠程處理,就爲該對象創建生存期租約。每個應用程序域都包含一個負責管理其域中的租約的租約管理器。租約管理器定期檢查所有租約以確定過期的租約時間。如果租約已過期,租約管理器將爲該對象遍歷它的主辦方列表並請求它們中是否有誰要續訂租約。如果沒有任何主辦方續訂該租約,租約管理器將移除該租約,該對象被刪除,其內存被垃圾回收機制回收。因此,如果對象被主辦方多次續訂租約或被客戶端持續調用,其生存期可以比其生存期租約長得多。

由於遠程對象的生存獨立於其客戶端的生存,因此簡單或輕量對象的租約(舉個例子來說)可以很長並被一些客戶端使用,前提是該租約被管理器或客戶端定期續訂。這種方法高效地使用租約,原因是分佈式垃圾回收所需的網絡通信量很小。另一方面,對於使用時間不太長和使用稀有資源的遠程對象來說,其租約的生存期可以很短,以至於客戶端用較短的時間頻繁地續訂其生存期。當所有客戶端都完成對遠程對象的處理時,.NET 遠程處理系統將很快刪除該對象。這種策略增加了網絡通信量以更有效地使用服務器資源。

使用租約管理遠程對象的生存期是引用計數的一種替換方法,引用計數在不可靠的網絡連接上可能是複雜而低效的。雖然可以將租約配置爲延長遠程對象的生存期以超過所需的精確長度,但是由於減少了專用於引用計數和進行 ping 操作的客戶端的網絡通信量,因而使租約在爲特定方案正確配置時成爲一種很有吸引力的解決方案。

租約有五個主要屬性:

  • InitialLeaseTime。它指定對象在租約管理器開始刪除對象的過程之前將保留在內存中的初始時間長度。在配置文件中,它是 <lifetime> 配置元素的 leaseTime 屬性。默認爲 5 分鐘。租約時間爲零則將租約設置爲具有無限長的生存期。

  • CurrentLeaseTime。它指定在租約過期之前所剩下的時間長度。當租約被續訂時,其 CurrentLeaseTime 被設置爲 CurrentLeaseTime 的最大值或 RenewOnCallTime

  • RenewOnCallTime。它指定對對象進行各個遠程調用後將 CurrentLeaseTime 設置爲的最大時間長度。默認爲 2 分鐘。

  • SponsorshipTimeout。它指定租約管理器被通知租約已過期時租約管理器等待主辦方響應的時間。如果主辦方未在指定的時間內響應,則移除該主辦方並調用另一主辦方。如果沒有其他主辦方,則租約過期,且垃圾回收器將處置該遠程對象。如果值爲“0”(TimeSpan.Zero),則租約將不註冊主辦方。默認爲 2 分鐘。

  • LeaseManagerPollTime。它是租約管理器在檢查過期的租約之後休眠的時間量。默認的 LeaseManagerPollTime 爲 10 秒鐘。

MBR 對象在其他應用程序域中被激活時創建租約。此時,當 ILease.CurrentState 屬性爲 LeaseState.Initial 時,可以設置租約的屬性。一旦設置,就不能直接更改它們。只可以從 ILease.Renew 調用中或者當租約管理器在主辦方上調用 ISponsor.Renewal 且該主辦方用一個 TimeSpan 響應時更改 CurrentLeaseTimeMarshalByRefObject 具有生存期租約的默認實現,且除非該租約在創建時被修改,否則租約屬性將始終相同。

修改租約屬性

可以通過兩種方式修改生存期租約屬性。可以聲明自定義生存期租約屬性,方法是重寫 MBR 對象中的 MarshalByRefObject.InitializeLifetimeService 以自己設置租約的屬性,或者將其重寫爲返回 null(Visual Basic 中爲 Nothing);後一種方法通知 .NET 遠程處理系統該類型的實例將具有無限長的生存期。您或者管理員還可以在特定的應用程序或計算機配置文件中的 <lifetime> 元素內指定該應用程序中所有對象的生存期屬性。

創建後,可以用三種方式續訂租約:

  • 客戶端直接調用 ILease.Renew 方法。

  • 如果設置了 ILease.RenewOnCallTime 屬性,則每個對遠程對象的調用都將爲租約續訂指定的時間。

  • 租約調用 ISponsor.Renewal 方法以請求續訂租約,而主辦方則以一個 TimeSpan 響應。

租約管理器

租約管理器的任務之一是定期檢查租約的時間是否過期。當租約的時間已過期時,該租約將接到通知並嘗試通過調用其主辦方來續訂自己。

租約管理器還維護一個租約正等待其答覆的主辦方的列表。如果主辦方未在 SponsorshipTimeOut 時間長度所指定的間隔內響應,則將其從主辦方列表中移除。

租約被允許過期時,它不再接受任何其他租約消息或主辦方返回的內容。租約的引用被從租約列表中移除,而且 .NET 遠程處理系統將把該對象引用從其內部表中移除。然後,垃圾回收系統將移除該租約和對象。

信道

信道是跨遠程處理邊界(無論是在應用程序域、進程還是計算機之間)在應用程序之間傳輸消息的對象。信道可以在終結點上偵聽入站消息,向另一個終結點發送出站消息,或者兩者都可以。這使您能夠插入各種各樣的協議,即使信道的另一端上沒有公共語言運行庫。

信道必須實現 IChannel 接口,該接口提供諸如 ChannelName ChannelPriority 這樣的信息性屬性。被設計爲在特定端口上偵聽特定協議的信道實現 IChannelReceiver,而被設計爲發送信息的信道實現 IChannelSender。TcpChannelHttpChannel 對於這兩種接口都加以實現,因此它們可用於發送或接收信息。

您可以以兩種方式將信道註冊到遠程處理基礎結構:

  • 如果您正在發佈可遠程處理的對象,則在註冊服務器對象之前調用 ChannelServices.RegisterChannel()。

  • 如果您正在使用可遠程處理的對象的功能,則在創建服務器對象的實例之前調用 ChannelServices.RegisterChannel()

信道還可以從遠程處理配置文件加載。

在客戶端,消息經過客戶端上下文鏈後,被傳遞到客戶端信道接收鏈。第一個信道接收器通常是格式化程序接收器;它將消息序列化爲流(然後該流將被沿着信道接收鏈傳遞到客戶端傳輸接收器)。然後客戶端傳輸接收器將此流寫出到網絡。

在服務器端,服務器傳輸接收器從網絡讀取請求,並將該請求流傳遞到服務器信道接收鏈。此鏈末端的服務器格式化程序接收器將該請求反序列化爲消息。然後將此消息傳遞到遠程處理基礎結構。

信道選擇

當客戶端在遠程對象上調用方法時,參數以及和調用有關的其他詳細信息將被通過信道傳輸到遠程對象。調用的任何結果均以相同的方式返回。客戶端可以選擇在服務器上註冊的任何信道與遠程對象通訊,這樣就使開發人員能夠自由地選擇最符合他們的需要的信道。也可以自定義任何現有信道或者生成使用不同通訊協議的新信道。信道選擇需要遵循以下規則:

  • 在可以調用遠程對象之前,服務器上的遠程處理系統必須註冊了至少一個信道。必須在註冊對象之前註冊信道。如果客戶端上沒有註冊信道,則遠程處理系統將選擇或創建一個以發送出站調用。

注意 如果客戶端需要回調函數,則必須在客戶端上註冊一個偵聽信道,並且必須將服務器配置爲使用一個兼容的信道。

  • 信道是針對每個應用程序域註冊的。單個進程可以包含多個應用程序域。當進程結束時,它註冊的所有信道都自動銷燬。

  • 信道名稱在應用程序域中必須是唯一的。例如,由於默認信道具有名稱,因此,若要在一個應用程序域中註冊兩個 HttpChannel 對象,就必須在註冊它們之前更改信道的名稱。下面的 C# 代碼示例對此進行了演示。

·                

·                

·                

  • 不能多次註冊在特定端口上偵聽的信道。雖然信道是針對每個應用程序域註冊的,但是同一臺計算機上的不同應用程序域不能註冊在同一個端口上偵聽的同一個信道。

  • 如果您不能確定是否有可用的端口,那麼在配置信道的端口時請使用“0”(零),遠程處理系統將爲您選擇一個可用的端口。

  • 客戶端可以使用任何已註冊的信道與遠程對象進行通訊。當客戶端嘗試連接到遠程對象時,遠程處理系統將確保該遠程對象被連接到正確的信道。客戶端負責在嘗試與遠程對象通訊之前調用 ChannelServices.RegisterChannel(),如果客戶端需要回調函數,那麼它必須註冊一個信道和一個端口。

當客戶端在代理上調用方法時,調用將被截獲並捆綁爲消息,然後被傳遞到 RealProxy 類的實例。RealProxy 類將消息轉發到消息接收器以進行處理。消息接收器與由遠程對象註冊的信道建立連接,並通過該信道將消息調度到起始應用程序域中。在那裏,該消息將被取消封送,並且將對遠程對象本身進行調用。

當遠程處理在客戶端的域中初始化遠程對象的代理時,將通過調用選定信道上的 IChannelSender.CreateMessageSink 從客戶端配置的信道中檢索一個能夠與該遠程對象通訊的消息接收器。

遠程處理系統的一個易引起混淆的方面是遠程對象和信道之間的關係。例如,如果對象僅在調用到達時才激活,SingleCall 遠程對象將如何偵聽要連接的客戶端呢?

這是可能的,部分原因在於遠程對象共享信道;遠程對象不擁有信道。承載遠程對象的服務器應用程序必須註冊它們所需要的信道以及它們要使用遠程處理系統公開的對象。信道註冊之後,將自動在指定的端口開始偵聽客戶端請求。對於同步調用的情況,將在消息調用期間維護來自客戶端的連接。由於每個客戶端連接都是在它自己的線程中處理的,因此單個信道可以同時服務於多個客戶端。

遠程處理示例:異步遠程處理

下面的示例應用程序說明遠程處理方案中的異步編程。該示例首先創建遠程對象的同步委託並且調用它來闡釋等待該返回的線程。然後,它使用異步委託和 ManualResetEvent 來調用遠程對象方法並等待響應。

該應用程序可在單臺計算機上運行或通過網絡運行。如果要在網絡上運行該應用程序,必須用遠程計算機的名稱替換客戶端配置中的“localhost”。

若要生成此示例,請保存下面的文件並在命令提示處鍵入下面的內容:

csc /t:library /out:ServiceClass.dll ServiceClass.cs

csc /r:ServiceClass.dll Server.cs

csc /r:ServiceClass.dll RemoteAsync.cs

然後,打開兩個指向同一目錄的命令提示符。在其中一個鍵入

   Server

在另一個鍵入:

   RemoteAsync

RemoteAsync.cs

Server.cs

ServiceClass.cs

Server.exe.config

SyncAsync.exe.config

總結

    上面是VS.NET中.NET遠程通信的一些概念和示例,給大家參考一下。有任何建議請MAIL我 [email protected]

 

發佈了33 篇原創文章 · 獲贊 0 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章