簡介 遠程方法調用發展到現在
已經有以下幾種框架實現
DCE/RPC
CORBA
DCOM
MTS/COM+
Java RMI
Java EJB
Web Services/SOAP/XML
RPC
NET Remoting
本文主要介紹了
NET遠程方法調用的原理
實現以及與微軟COM/DCOM實現的異同點
框架 Microsoft
NET Remoting 提供了一種允許對象通過應用程序域與另一對象進行交互的框架
眾所周知
Web服務僅僅提供了一種簡單的容易理解的方法來實現跨平台
跨語言的交互
而DotNet Remoting相對於Web服務就像Asp相對於CGI那樣
實現了一種質的轉變
DotNet Remoting提供了一個可擴展的框架
它可以選擇不同的傳輸機制(HTTP和TCP是內置的)
不同的編碼方式(SOAP以及二進制代碼)
安全設置(IIS或SSL)
同時提供了多種服務
包括激活和生存期支持
遠程方法調用 對於遠程方法調用來說
最直接的問題恐怕是
一個本地方法
推而廣之
一個本地對象
如果放在網絡環境中
如何傳遞這個方法的調用
返回
如何傳遞這個對象的請求
雖然對於應用開發人員來說這個並不是必不可少的事
但對於我們學習分布式操作系統來說
我想這是應該搞清楚的
我們知道
DCOM協議也被稱為對象RPC
它建立在DCE RPC協議基礎上
也就是說
在網絡傳輸這一層
它必須使用特殊的協議
另外Windows RPC 機制要求熟悉的類型和使用 IDL 工具的封送處理知識
並向開發人員公開 RPC 客戶端和服務器存根的管理
Remoting 在為
NET 提供 RPC 時要容易得多
而且由於使用簡單易懂的
NET 數據類型
從而消除了早期 RPC 機制中存在的類型不匹配的情況(這是一個非常大的威脅)
配置為使用 HTTP 或 TCP 協議
並使用 XML 編碼的 SOAP 或本機二進制消息格式進行通信
開發人員可以構建自定義的協議(通道)或消息格式(格式化程序)
並在需要時由 Remoting 框架使用
服務器和客戶端組件都可以選擇端口
就象可以選擇通信協議一樣
由此帶來的一個好處是
很容易建立並運行基本的通信
下圖中描述了
Net Remoting的五要素
代理
在Client端偽裝為Remote Objects並轉發對Remote Objects的調用
Message
消息對象包含了執行Remote Methods調用的必要數據參數
Message Sink/Channel Sink
在Remote調用中
Message Sink允許定制消息處理流程
這是
Net Remoting內置的可擴展特性
Formatter
也是Message Sink
用來序列化消息
已適於網絡傳輸
如SOAP
Transport Channel
也是Message Sink
用來傳輸序列化的消息到遠程進程
如HTTP
當訪問Remote Objects時
Client端application並不處理真實對象的引用
而是僅僅調用Proxy對象的方法
Proxy對象提供與Remote Objects相同的接口
偽裝成Remote Objects
Proxy對象自己並不執行任何方法
而是以消息對象(Message Object)的形式轉發每一個方法調用給
Net Remoting Framework
在類型支持方面
DCOM提供了一套復雜的列集和散集機制
他建立在RPC的基礎上
由於RPC被定義為DCE標准的一部分
而DCE RPC定義了所有常用的數據類型的數據表達方法
即網絡數據表示法
為了使存根(stub)代碼和代理對象能夠正確地對參數和返回結果也進行列集和散集
它們應該使用一致的數據表示法NDR
以便在不同的操作系統環境下也能夠遠程調用
This figure is from the book named Advanced
Net Remoting
反過來
我們再看看
NET Remoting 強大的類型操作
Net Remoting 支持所有托管的類型
類
接口
枚舉
對象等
這通常被稱為
多類型保真
這裡的關鍵在於
如果客戶端和服務器組件都是在應用程序域中運行的 CLR 托管的對象
則數據類型的互操作是不成問題的
從根本上講
我們擁有的是一個封閉的系統
會話的兩端可以完全被理解
因此我們可以充分利用這一事實
處理好用於通信的數據類型和對象
在各種系統並存的情況下
我們需要考慮系統之間的互操作性
對於可互操作的數據類型
我們要謹慎處理
例如
Web 服務數據類型的定義要基於 XML 架構定義 (XSD) 關於數據類型的說明
任何可以使用 XSD 進行描述並可以在 SOAP 上進行互操作的類型都可以使用
但是
這也確實使得某些數據類型不能使用
代理 代理對象偽裝成一個遠程對象
並且向本地提供遠程對象相同的接口
客戶端應用程序與處理遠程
真實
對象的應用(包括內存引用
指針
等等)
都是通過代理對象實現的
代理對象當然並不自己完成方法調用
它將請求作為消息對象傳給
NET Framework
在這一方面
Net Remoting 和DCOM思想上是一致的
當某個客戶端激活一個遠程對象時
框架將創建 TransparentProxy 類的一個本地實例(該類中包含所有類的列表與遠程對象的接口方法)
因為 TransparentProxy 類在創建時用 CLR 注冊
所以代理上的所有方法調用都被運行時截取
這時系統將檢查調用
以確定其是否為遠程對象的有效調用
以及遠程對象的實例是否與代理位於同一應用程序域中
如果對象在同一個應用程序域中
則簡單方法調用將被路由到實際對象
如果對象位於不同的應用程序域中
將通過調用堆棧中的調用參數的 Invoke 方法將其打包到 IMessage 對象並轉發到 RealProxy 類中
此類(或其內部實現)負責向遠程對象轉發消息
TransparentProxy 類和 RealProxy 類都是在遠程對象被激活後在後台創建的
但只有 TransparentProxy 返回到客戶端
在代理對象創建時
需要引用Client端的Messag Sink Chain
Sink Chain的第一個Sink對象的引用保存在RealProxy對象的Identity屬性
如下圖所示
所以
在下面這段代碼調用new或者GetObject獲得對象後
對象obj將會指向
TransparentProxy對象
HttpChannel channel = new HttpChannel();
ChannelServices
RegisterChannel(channel);
SomeClass obj = (SomeClass) Activator
GetObject(
type of(SomeClass)
);
消息 當一次函數調用指向遠程對象的引用時
TransparentProxy創建一個MessageData對象並且將它傳給RealProxy對象的PrivateInvoke()調用
RealProxy相應地生成一個新的Message對象並且以MessageData對象為參數調用其InitFields()方法
Message將會解析MessageData對象中地指針進行相應地函數調用
當處理結束時
將會返回一個包含回應消息的IMessage對象
RealProxy將會調用它自己的HandleReturnMessage()方法
該方法檢查參數並且調用PropagateOutParameters()方法
當處理結束後RealProxy將會從它的PrivateInvoke()方法中返回
IMessage將會返回給TransparentProxy
CLR保證函數返回值與其返回格式相符
所以對於應用程序來說
它僅僅認為這是一個一般方法的調用
返回
這正是分布式的最終要求
可以看到
NET Remoting與DCOM的底層機制已經完全不同了
DCOM的一次方法調用
需要經過列集(marshaling)和散集(unmarshaling)的處理
包括創建代理對象和轉載存根代碼等
但是可以看到
NET做為DCOM的下一代
在基本思想上和DCOM是一脈相承的
在我學習到現在的體會看來
NET面向Web服務的RPC機制的確是一大革新
讓我們看看IMessage怎麼進行傳遞的
這是一個消息穿過Transport Channel(也就是Message Sink)的實例
首先是SOAP遠程調用的HTTP請求
POST /MyRemoteObject
soap HTTP/
User
Agent: Mozilla/
+(compatible; MSIE
; Windows
; MS
NET
Remoting;
MS
NET CLR
)
SOAPAction:
#
setValue
Content
Type: text/xml; charset=
utf
Content
Length:
Expect:
continue
Connection: Keep
Alive
Host: localhost
然後是一個對於一個遠程對象setValue(int):
POST /MyRemoteObject
soap HTTP/
User
Agent: Mozilla/
+(compatible; MSIE
; Windows
; MS
NET
Remoting;
MS
NET CLR
)
SOAPAction:
#
setValue
Content
Type: text/xml; charset=
utf
Content
Length:
Expect:
continue
Connection: Keep
Alive
Host: localhost
<SOAP
ENV:Envelope
xmlns:xsi=
instance
xmlns:xsd=
xmlns:SOAP
ENC=
xmlns:SOAP
ENV=
SOAP
ENV:encodingStyle=
xmlns:i
=
>
<SOAP
ENV:Body>
<i
:setValue id=
ref
>
<newval>
From:http://tw.wingwit.com/Article/program/Java/hx/201311/25973.html