直播中
摘要:本文介紹 Microsoft .NET Romoting 框架的基本原理。除了介紹組成 .NET Romoting 框架的主要組件外,還介紹 .NET Remoting 與分布式對象通信的幾種方案。
目錄
簡介
.NET Remoting 對象
集成 .NET Remoting 對象
.NET Remoting 元數(shù)據(jù)和配置文件
.NET Remoting 方案
總結(jié)
其他資料
簡介
Microsoft® .NET Remoting 是一個豐富的、可擴(kuò)展的框架,它使得處于不同 AppDomain、不同過程和不同機(jī)器上的對象可以實(shí)現(xiàn)無縫通信。.NET Remoting 提供的編程模型和運(yùn)行時支持功能強(qiáng)大而又易于使用,能夠?qū)崿F(xiàn)透明的交互操作。本文將瀏覽 Remoting 體系結(jié)構(gòu)的不同構(gòu)造塊,并研究一些應(yīng)用 .NET Remoting 的常見方案。.NET Remoting 對象可以作為一種 Web 服務(wù)使用(請參閱 MSDN Magazine 文章“可編程 Web:Web 服務(wù)為 Microsoft .NET 框架提供構(gòu)造塊(英文)”,允許從任何能夠執(zhí)行 SOAP 調(diào)用的客戶端訪問 .NET Remoting 對象。有關(guān) .NET Remoting 的概述信息,請先閱讀文章“Microsoft .NET Remoting:技術(shù)概述(英文)”。
.NET Remoting 對象
有三類對象可以被配置為 .NET 遠(yuǎn)程對象。您可以根據(jù)應(yīng)用程序的需要選擇對象類型。本節(jié)將詳細(xì)介紹這些對象。
“單一調(diào)用對象”僅為一個請求提供服務(wù)。在需要對象完成的工作量有限,并且不必存儲狀態(tài)信息的情況下,單一調(diào)用對象非常有用。單一調(diào)用對象可以被配置為負(fù)載平衡模式。在方法調(diào)用之間,單一調(diào)用對象不能保留狀態(tài)信息。
“單一元素對象”可以為多個客戶端提供服務(wù),因此可以通過保存客戶端調(diào)用的狀態(tài)信息來實(shí)現(xiàn)數(shù)據(jù)共享。當(dāng)客戶端需要明確地共享數(shù)據(jù),并且不能忽略創(chuàng)建和維護(hù)對象的開銷時,這種對象非常有用。
“客戶端激活的對象 (CAO)”是服務(wù)器端的對象,收到來自客戶端的請求時會激活這些對象。這種激活服務(wù)器對象的方法與傳統(tǒng)的 COM coclass 激活方法很相似。當(dāng)客戶端使用“new”操作符請求服務(wù)器對象時,將向遠(yuǎn)程應(yīng)用程序發(fā)送一個激活請求消息。隨后,服務(wù)器將創(chuàng)建被請求類的實(shí)例,并向調(diào)用它的客戶端應(yīng)用程序返回 ObjRef??蛻舳藢⑹褂么?ObjRef 創(chuàng)建代理??蛻舳说姆椒ㄕ{(diào)用將在代理上執(zhí)行??蛻舳思せ畹膶ο罂梢詾槠涮囟ǖ目蛻舳耍ú荒芸缭讲煌目蛻舳藢ο螅┍4娣椒ㄕ{(diào)用之間的狀態(tài)信息。每次“new”調(diào)用都會返回服務(wù)器類型的獨(dú)立實(shí)例的代理。
使用 .NET Remoting 傳遞對象
在 .NET Remoting 中,可以通過以下方式在應(yīng)用程序之間傳遞對象:
作為方法調(diào)用的參數(shù)
示例:public int myRemoteMethod (MyRemoteObject myObj)
方法調(diào)用的返回值
示例:public MyRemoteObject myRemoteMethod(String myString)
訪問 .NET 組件的屬性或字段得到的值
示例:myObj.myNestedObject
對于 Marshal By Value (MBV) 的對象,當(dāng)它在應(yīng)用程序之間傳遞時,將創(chuàng)建一個完整的副本。
對于 Marshal By Reference (MBR) 的對象,當(dāng)它在應(yīng)用程序之間傳遞時,將創(chuàng)建該對象的引用。當(dāng)對象引用 (ObjRef) 到達(dá)遠(yuǎn)程應(yīng)用程序后,將轉(zhuǎn)變成“代理”返回原始對象。
簡單 .NET Remoting 服務(wù)器對象的代碼示例
using System;
using System.Runtime.Remoting;
namespace myRemoteService
{
// 有名的 Web 服務(wù)對象
public class myRemoteObject : MarshalByRefObject
{
// myRemoteMethod 方法
public String myRemoteMethod(String s)
{
return "Hello World";
}
}
}
訪問此對象的客戶端代碼示例
using System;
using System.Runtime.Remoting;
using myRemoteService;
public class Client
{
public static int Main(string[] args)
{
ChannelServices.RegisterChannel(new HTTPChannel(7055));
// 創(chuàng)建 myRemoteObject 類的實(shí)例
myRemoteObject myObj = ( myRemoteObject)Activator.GetObject(typeof(myRemoteObject),
"http://myHost:7021/host/myRemoteObject.soap");
myObj. myRemoteMethod ("Hello World");
return 0;
}
}
租用生存期
對于那些具有在應(yīng)用程序之外傳送的對象引用的對象,將創(chuàng)建一個租用。租用具有一個租用時間。如果租用時間為 0,則租用過期,對象將斷開與 .NET Romoting 框架的連接。一旦 AppDomain 內(nèi)部所有的對象引用都被釋放,則下一個 GC 發(fā)生時對象將被回收。租用控制了對象的生存期。
對象有默認(rèn)的租用階段。當(dāng)客戶端要在同一服務(wù)器對象中維護(hù)狀態(tài)信息時,可以通過許多方法擴(kuò)展租用階段,使對象繼續(xù)生存。
可以將服務(wù)器對象的租用時間設(shè)置為無限,這樣 Remoting 在垃圾回收周期中就不會回收此對象。
客戶端可以調(diào)用 RemotingServices.GetLifetimeService 方法,以從 AppDomain 的租用管理器獲取服務(wù)器對象的租用時間。然后,客戶端便可以通過 Lease 對象來調(diào)用 Lease.Renew 方法,以延長租用時間。
客戶端可用 AppDomain 的租用管理器為特定的租用注冊負(fù)責(zé)人。當(dāng)遠(yuǎn)程對象租用過期時,租用管理器將通知負(fù)責(zé)人提出更新租用的申請。
如果設(shè)置了 ILease::RenewOnCallTime 屬性,則每次調(diào)用遠(yuǎn)程對象時,都會用 RenewOnCallTime 屬性指定的時間更新租用時間。
單一調(diào)用/單一元素對象 客戶端激活的對象
客戶端激活代碼(客戶端所需的代碼)
有關(guān)詳細(xì)信息,請參閱配置文件的相關(guān)小節(jié)
a) Activator.GetObject()
b) new() 及 CFG 文件
客戶的 CFG 文件引用下列 URL:
Foo= http://localhost:80/ObjectZone/Foo.soap
a) Activator.CreateInstance()
b) new() 及 CFG 文件
客戶的 CFG 文件引用服務(wù)器數(shù)據(jù)庫以及服務(wù)器應(yīng)用程序的 URL,并提供對象 URI??蛻舳藘?nèi)置了對這些數(shù)據(jù)庫的引用:
Assembly#MyObjectLibrary#ObjectZone#
MyObjectLibrary.Baz
RemoteApplication#ObjectZone#
HTTP://localhost:80/ObjectZone
服務(wù)器對象的激活 在首次調(diào)用方法之前,不會在網(wǎng)絡(luò)上發(fā)送激活消息 當(dāng)客戶端創(chuàng)建對象,并且在客戶端生成代理之后,激活消息將發(fā)送至服務(wù)器。支持帶參數(shù)的構(gòu)造函數(shù)。
服務(wù)器對象的生存期 生存期由服務(wù)器上的配置設(shè)定,可以為 SingleCall 或 Singleton 生存期在下列兩個事件之一發(fā)生時結(jié)束:
a) 租用過期
b) 客戶釋放在服務(wù)器對象上的引用時
服務(wù)器端注冊 a) 使用配置文件來指定類型(SingleCall 或 Singleton)
b) 使用 RegisterWellKnownType() API 注冊類型
使用配置文件來導(dǎo)出客戶端激活的對象
有關(guān)詳細(xì)信息,請參閱配置文件的相關(guān)小節(jié)
模型的優(yōu)點(diǎn) a) 可以利用服務(wù)器組件的基類或接口定義公共語言運(yùn)行時元數(shù)據(jù)來編譯客戶端
b) 在服務(wù)器端執(zhí)行有限操作的情況下很有用處
c) 單一調(diào)用對象不保存狀態(tài)信息,所以易于在負(fù)載平衡系統(tǒng)中進(jìn)行配置
d) 單一元素對象可以在多個客戶對象之間維護(hù)狀態(tài)信息
a) 服務(wù)器對象的調(diào)用與傳統(tǒng)的 COM“coclass”類似
b) 客戶端可以更加靈活地管理服務(wù)器對象的生存期
c) 客戶端能夠向被創(chuàng)建的對象傳遞構(gòu)造函數(shù)參數(shù)
d) 服務(wù)器對象可以為其特定客戶端在多次方法調(diào)用之間保留狀態(tài)信息
集成 .NET Remoting 對象
.NET Remoting 對象可以集成在:
托管可執(zhí)行項(xiàng):.NET Remoting 對象可以集成在任何常規(guī)的 .NET EXE 或托管服務(wù)中。
IIS:Remoting 對象可以集成在 Internet Information Server (IIS) 中。默認(rèn)情況下,集成在 IIS 中的 Remoting 對象通過 HTTP 通道接收消息。要在 IIS 中集成 Remoting 對象,必須創(chuàng)建一個虛擬根目錄,并將 remoting.cfg 文件復(fù)制到其中。包含遠(yuǎn)程對象的可執(zhí)行文件或 DLL 應(yīng)放置在 IIS 根目錄下的 bin 目錄中。需要注意的是,IIS 根目錄的名稱應(yīng)該與配置文件中指定的應(yīng)用程序名稱相同。當(dāng)應(yīng)用程序接收到第一個消息時,遠(yuǎn)程配置文件將自動加載。使用這種方法,可以將 .NET Remoting 對象作為 Web 服務(wù)提供。
Remoting.cfg 文件示例:
Name#HelloService
WellKnownObject#HelloService.Hello#HelloService#HelloService/
Hello.soap#SingleCall
其格式為:
Name#[Name of the Application]
WellKnownObject#[FullTypeName]#[AssemblyName]#[ObjectURI]#[ObjectMode]
.NET 組件服務(wù):.NET Remoting 對象可以集成在 .NET 組件服務(wù)基礎(chǔ)結(jié)構(gòu)中,從而利用各種 COM+ 服務(wù),例如:事務(wù)、JIT、對象池等。
有關(guān)詳細(xì)信息,請參閱 Microsoft .NET 框架組件服務(wù),第 1 部分(英文)。
通道服務(wù) (System.Runtime.Remoting.Channels)
.NET 應(yīng)用程序和 AppDomains 之間使用消息進(jìn)行通信。.NET “通道服務(wù)”為這一通信過程提供了底層傳輸機(jī)制。
.NET 框架提供了 HTTP、TCP 和 SMTP 通道,但是第三方也可以編寫并使用自己的通道。默認(rèn)情況下,HTTP 和 SMTP 通道使用 SOAP 進(jìn)行通信,而 TCP 通道使用二進(jìn)制有效負(fù)載。
通過使用可以編寫到集成混合應(yīng)用程序中的自定義通道,可以插入通道服務(wù)(使用 IChannel)。
加載通道服務(wù)的代碼示例
public class myRemotingObj
{
HTTPChannel httpChannel;
TCPChannel tcpChannel;
public void myRemotingMethod()
{
httpChannel = new HTTPChannel();
tcpChannel = new TCPChannel();
ChannelServices.RegisterChannel(httpChannel);// 注冊 HTTP 通道
ChannelServices.RegisterChannel(tcpChannel);// 注冊 TCP 通道
}
}
序列化格式化程序 (System.Runtime.Serialization.Formatters)
.NET 序列化格式化程序?qū)?.NET 應(yīng)用程序和 AppDomains 之間的消息進(jìn)行編碼和解碼。在 .NET 運(yùn)行時中有兩個本地格式化程序,分別為 Binary (System.Runtime.Serialization.Formatters.Binary) 和 SOAP (System.Runtime.Serialization.Formatters.Soap)。
序列化格式化程序是可插入的,方法是實(shí)例化 IRemotingFormatter 接口,并將其插入到上文介紹的通道中。這樣,您可以靈活地選擇通道和格式化程序的組合方式,采用最適合應(yīng)用程序的方案。本文后面的小節(jié)將討論這一問題。
例如:您可以采用 HTTP 通道和 Binary 格式化程序(串行化二進(jìn)制數(shù)據(jù)),也可以采用 TCP 通道和 SOAP 格式化程序。
Remoting 上下文
“上下文”是一個包含共享公共運(yùn)行時屬性的對象的范圍。一些有關(guān)上下文屬性的例子是與同步和線程緊密相關(guān)的。當(dāng) .NET 對象被激活時,運(yùn)行時將檢查當(dāng)前的上下文是否一致,如果不一致,將創(chuàng)建新的上下文。多個對象可以同時在一個上下文中運(yùn)行,并且一個 AppDomain 中可以有多個上下文。
一個上下文中的對象調(diào)用另一個上下文中的對象時,調(diào)用將通過上下文代理來執(zhí)行,并且會受組合上下文屬性的強(qiáng)制策略影響。新對象的上下文通常是基于類的元數(shù)據(jù)屬性選擇的。
可以與上下文綁定的類稱作上下文綁定類。上下文綁定類可以具有稱作“上下文屬性”的專用自定義屬性。上下文屬性是完全可擴(kuò)展的,您可以創(chuàng)建這些屬性并將它們附加到自己的類中。與上下文綁定的對象是從 System.ContextBoundObject 導(dǎo)出的。
.NET Remoting 元數(shù)據(jù)和配置文件
.NET 框架使用元數(shù)據(jù)和程序集來存儲有關(guān)組件的信息,使得多語言編程技術(shù)成為可能。.NET Remoting 使用元數(shù)據(jù)動態(tài)地創(chuàng)建代理對象。在客戶端創(chuàng)建的代理對象的成員與原始類相同。但是,代理對象的實(shí)現(xiàn)僅僅將所有的請求通過 .NET Remoting 運(yùn)行時轉(zhuǎn)發(fā)給原始對象。序列化格式化程序使用元數(shù)據(jù)將方法調(diào)用轉(zhuǎn)換為有效負(fù)載數(shù)據(jù)流,并將有效負(fù)載數(shù)據(jù)流轉(zhuǎn)換回方法調(diào)用。
客戶端可以通過以下方法獲取訪問遠(yuǎn)程對象所需的元數(shù)據(jù)信息:
服務(wù)器對象的“.NET 程序集”- 服務(wù)器對象可以創(chuàng)建元數(shù)據(jù)程序集,并將其分發(fā)給客戶端。在編譯客戶端對象時,客戶端對象可以引用這些程序集。在客戶端和服務(wù)器都是托管組件的封閉環(huán)境中,這種方法非常有用。
遠(yuǎn)程對象可以提供 WSDL(請參閱 Web 服務(wù)說明語言 [WSDL] 1.0 [英文])文件,用于說明對象及其方法。所有可以根據(jù) WSDL 文件讀取和生成 SOAP 請求的客戶端都可以調(diào)用此對象,或使用 SOAP 與之通信。使用與 .NET SDK 一同分發(fā)的 SOAPSUDS.EXE 工具,.NET Remoting 服務(wù)器對象可以生成具有元數(shù)據(jù)功能的 WSDL 文件。當(dāng)組織希望提供所有客戶都能訪問和使用的公共服務(wù)時,這種方法非常有用。
.NET 客戶可以使用 SOAPSUDS 工具從服務(wù)器上下載 XML 架構(gòu)(在服務(wù)器上生成),生成僅包含元數(shù)據(jù)(沒有代碼)的源文件或程序集。您可以根據(jù)需要將源文件編譯到客戶端應(yīng)用程序中。如果多層應(yīng)用程序中某一層的對象需要訪問其他層的遠(yuǎn)程對象,則經(jīng)常使用此方法。
“配置文件”(.CFG 文件)用于指定特定對象的各種 Remoting 特有信息。通常情況下,每個 AppDomain 有自己的 CFG 文件。使用 CFG 文件有助于實(shí)現(xiàn)位置的透明性。CFG 文件中的詳細(xì)信息也可以通過編程來指定。使用 CFG 文件的主要好處在于,它將與客戶端代碼無關(guān)的配置信息分離出來,這樣,在日后更改時僅需要修改 CFG 文件,而不用編輯和重新編譯源代碼。.NET Remoting 的客戶端和服務(wù)器對象都使用配置文件。
典型的 CFG 文件包含以下信息及其他信息:
集成應(yīng)用程序信息
對象名稱
對象的 URI
注冊的通道(可以同時注冊多個通道)
服務(wù)器對象的租用時間信息
示例配置文件(請注意,在后續(xù)版本中可能會采用 XML 格式):
Name#MyRemoteApp
myRemoteObj = HTTP://myCompany:80/MyRemoteApp/myRemoteObj.soap
Channel#System.Runtime.Remoting#System.Runtime.Remoting.Channels.TCP.TCPChannel
Channel#System.Runtime.Remoting#System.Runtime.Remoting.Channels.HTTP.HTTPChannel
.NET Remoting 方案
了解 .NET Remoting 如何工作之后,讓我們來考察不同的方案,分析如何在不同的方案中充分發(fā)揮 .NET Remoting 的性能。下表列出了可能的客戶端/服務(wù)器組合,以及默認(rèn)情況下采用的底層協(xié)議和有效負(fù)載。請注意,.NET Remoting 框架是可擴(kuò)展的,您可以編寫自己的通信通道和序列化格式化程序。
客戶端 服務(wù)器 有效負(fù)載 協(xié)議
.NET 組件 .NET 組件 SOAP/XML http
.NET 組件 .NET 組件 二進(jìn)制 TCP
托管/非托管 .NET Web 服務(wù) SOAP/XML http
.NET 組件 非托管的傳統(tǒng) COM 組件 NDR(網(wǎng)絡(luò)數(shù)據(jù)表示形式) DCOM
非托管的傳統(tǒng) COM 組件 .NET 組件 NDR DCOM
任何客戶端 <-> .NET,使用 HTTP-SOAP
Web 服務(wù)是可以通過 URL 尋址的資源,并通過編程向需要使用這些資源的客戶端返回信息??蛻舳耸褂?Web 服務(wù)時不必考慮其實(shí)現(xiàn)細(xì)節(jié)。Web 服務(wù)使用稱為“合約”的嚴(yán)格定義的接口,此接口采用 Web 服務(wù)描述語言 (WSDL) 文件定義。有關(guān) WSDL 的詳細(xì)信息,請參閱 Web 服務(wù)描述語言 (WSDL) 1.0(英文)。
可以將 .NET Remoting 對象集成在 IIS 中,使它們作為 Web 服務(wù)使用。任何可以使用 WSDL 文件的客戶端,都可以按照 WSDL 文件中指定的約定對遠(yuǎn)程對象執(zhí)行 SOAP 調(diào)用。IIS 使用 ISAPI 擴(kuò)展將這些請求路由到相應(yīng)的對象。這樣,遠(yuǎn)程對象就可以作為 Web 服務(wù)對象來使用,從而充分發(fā)揮 .NET 框架基礎(chǔ)結(jié)構(gòu)的作用。如果您希望不同平臺/環(huán)境的程序均能夠訪問對象,則可以采用這種配置。有關(guān) Web 服務(wù)的詳細(xì)信息,請參閱可編程 Web:Web 服務(wù)為 Microsoft .NET 框架提供構(gòu)造塊(英文)。這種配置方法便于客戶端通過防火墻訪問您的 .NET 對象。
圖 1:通過 HTTP-SOAP 調(diào)用 Remoting 對象的 Web 服務(wù)的客戶端示例
.NET <-> .NET,使用 SOAP-HTTP 通道
默認(rèn)情況下 HTTP 通道使用 SOAP 格式化程序,因此,如果客戶端需要通過 Internet 訪問對象,則可以使用 HTTP 通道。由于這種方法使用 HTTP,所以允許客戶端通過防火墻遠(yuǎn)程訪問 .NET 對象。只需按前一節(jié)中介紹的方法將這些對象集成在 IIS 中,即可將其配置為 Web 服務(wù)對象。隨后,客戶端就可以讀取這些對象的 WSDL 文件,以便使用 SOAP 與 Remoting 對象通信。
.NET <-> .NET,使用 TCP 通道
默認(rèn)情況下,TCP 通道使用二進(jìn)制格式化程序。此格式化程序以二進(jìn)制格式進(jìn)行數(shù)據(jù)的序列化,并使用原始套接字在網(wǎng)絡(luò)中傳送數(shù)據(jù)。如果對象部署在受防火墻保護(hù)的封閉環(huán)境中,則此方法是理想的選擇。該方法使用套接字在對象之間傳遞二進(jìn)制數(shù)據(jù),因此性能更好。由于它使用 TCP 通道來提供對象,因此具有在封閉環(huán)境中開銷較小的優(yōu)點(diǎn)。由于防火墻和配置問題,此方法不能在 Internet 上使用。
圖 2:通過 TCP 通道在多個機(jī)器之間調(diào)用 Remoting 對象的客戶端示例
.NET <-> 非托管的 COM 組件 <-> .NET
您可以通過 COM Interop Service 調(diào)用非托管的傳統(tǒng) COM 組件。當(dāng) .NET Remoting 客戶端對象創(chuàng)建 COM 對象的實(shí)例時,對象通過運(yùn)行時可調(diào)用包裝程序 (RCW) 來提供,而 RCW 則作為真實(shí)非托管對象的代理。這些包裝程序看起來和 .NET 客戶端的任何其他托管類一樣,但實(shí)際上,它們僅僅是托管 (.NET) 和非托管 (COM) 代碼之間的封送調(diào)用。
類似地,您可以將 .NET Remoting 服務(wù)器對象提供給傳統(tǒng) COM 客戶端。當(dāng) COM 客戶端創(chuàng)建 .NET 對象的實(shí)例時,對象通過 COM 可調(diào)用包裝程序 (CCW) 來提供,而 RCW 則作為真實(shí)非托管對象的代理。
這兩種方案都使用 DCOM 通信。如果環(huán)境中既有傳統(tǒng)的 COM,又有 .NET 組件,那么這種互操作性將為您提供便利。有關(guān)此主題的詳細(xì)信息,請參閱 COM 互操作性規(guī)范(英文)。
總結(jié)
Microsoft .NET 框架提供了強(qiáng)大、可擴(kuò)展、不依賴于語言的框架,用于開發(fā)可靠、可伸縮的分布式系統(tǒng)。.NET Romoting 框架提供了根據(jù)系統(tǒng)需求進(jìn)行遠(yuǎn)程交互的強(qiáng)大手段。.NET Remoting 實(shí)現(xiàn)了與 Web 服務(wù)的無縫集成,并有一些方法可以提供 .NET 對象以進(jìn)行多平臺訪問的方法。