標籤:c style class blog code java
.Net組件程式設計之遠程調用(一)
1應用程式定義域
我們知道我們寫的C#代碼是在作業系統邏輯體繫結構中最上層的,然而作業系統本身是不會認識C#代碼的,它只認識機器代碼。那我們寫的程式經過編譯後是編譯成IL的,是怎麼啟動並執行呢?實際是在一個託管的環境下啟動並執行,是.NET提供的支援,作業系統是不會識別IL的,這中間就需要一個橋樑:應用程式定義域。作業系統中的進程是資源單位,應用程式定義域的執行使用當然也要佔用空間使用資源了,所以是物理進程承載著應用程式定義域的,而且這種承載關係並不是一對一的。
圖:應用程式定義域
使用應用程式定義域這樣的機制,是有許多好處的。比如說用戶端在調用其他組件的時候可以建立一個應用程式定義域,然後在建立的應用程式定義域中載入組件進行操作等等,即使被調用的組件發生一些致命的錯誤也不會導致用戶端崩潰,有效進行了錯誤隔離。還有一些資料互動傳輸上的效能差異等等,這裡不做詳細的闡述了。
2.NET Remoting
.NET Remoting是一種基於.NET平台的分布式系統架構,所瞭解的就是用於資料轉送。 說幾句它被使用的局限性很大,受到了平台的限制,當然如果僅僅是這樣是不能否定它的強大和幾乎無限擴充的架構體系,無論在哪一個環節你都可以自己來實現一些自訂的功能。會在下個篇幅稍作講解。
3.AppDomain
在.NET中用AppDoMain類來表示應用程式定義域,也提供了擷取當前應用程式定義域的方法,可以直接使用AppDoMain類的靜態屬性CurrentDomain來擷取到當前程式所在的應用程式定義域,這是一種方法,還額外提供一種了,就是Thread類的GetDomain()靜態方法也是可以擷取到的。
3.1 在當前應用程式定義域中建立對象
1 namespace RemoteServer 2 public class class1 3 { 4 private string appDoMainName; 5 6 public class1() 7 { 8 appDoMainName = AppDomain.CurrentDomain.FriendlyName; 9 }10 11 public void Writer()12 {13 Console.WriteLine(appDoMainName);14 }15 }
class1中建構函式是擷取當前應用程式定義域的名稱,並且是在Writer()方法中輸出到控制台介面中,
using RemoteServer;namespace RemoteCase{ AppDomain appDoMain = AppDomain.CurrentDomain; class1 cls1 = (class1)appDoMain.CreateInstanceFromAndUnwrap("RemoteServer.dll", "RemoteServer.class1"); cls1.Writer();}
圖3-1
這裡使用了AppDomain中的靜態方法CreateInstanceFromAndUnwrap(),因為當前項目已經引用了RemoteServer程式集,所以第一個參數只是一個顯示的名稱,並不是全路徑,在調用方法的時候,應用程式定義域會載入程式集,用於擷取到中繼資料。
3.2 在建立應用程式定義域中建立對象
1 namespace RemoteServer 2 public class class1:MarshalByRefObject 3 { 4 private string appDoMainName; 5 6 public class1() 7 { 8 appDoMainName = AppDomain.CurrentDomain.FriendlyName; 9 }10 11 public void Writer()12 {13 Console.WriteLine(appDoMainName);14 }15 }
1 using RemoteServer;2 3 AppDomain appDoMain = AppDomain.CurrentDomain;4 AppDomain newDoMain = AppDomain.CreateDomain("NewDoMain");5 class1 cls1 = (class1)newDoMain.CreateInstanceFromAndUnwrap("RemoteServer.dll", "RemoteServer.class1");6 cls1.Writer();
圖3-2
3.3 拆包遠程對象
圖3-3-1
這段代碼是3.2中的代碼,cls1並不是class1類型本身,而是代理,訪問遠程對象都是通過代理完成的,這麼屌炸天的.NET當然提供最佳化,將建立遠程對象和在用戶端建立代理分離,這樣可以在你建立了一個遠程對象之後再建立代理。 AppDomain類提供了一套CreateInstance()方法來建立對象,但是都以ObjectHandle的形式返回一個遠程物件控點(意思就是遠程對象的唯一標示,這個控制代碼能代表遠程對象)
ObjectHandle對象實現了System.Runtime.Remoting命名空間下的IObjectHandle介面:
1 namespace RemoteServer 2 public class class1:MarshalByRefObject 3 { 4 private string appDoMainName; 5 6 public class1() 7 { 8 appDoMainName = AppDomain.CurrentDomain.FriendlyName; 9 }10 11 public void Writer()12 {13 Console.WriteLine(appDoMainName);14 }15 16 }
1 using RemoteServer; 2 3 AppDomain appDoMain = AppDomain.CurrentDomain; 4 AppDomain newDoMain = AppDomain.CreateDomain("NewDoMain"); 5 IObjectHandle objecthandle; 6 objecthandle = newDoMain.CreateInstance("RemoteServer", "RemoteServer.class1"); 7 8 RemoteServer.class1 cls1 = objecthandle.Unwrap() as RemoteServer.class1; 9 10 cls1.Writer();
一般情況下是不需要手動拆包物件控點的,這樣做的好處只是可以延後載入RemoteServer程式集,只有在 objecthandle.Unwrap()的時候才會建立代理,而建立代理必須需要對象中繼資料。
4遠程物件類型
一般情況下,被引用對象和用戶端同在一個應用程式定義域,這樣的情況下不涉及到代理,也不會用到什麼遠程調用,
而是直接引用對象,如果當你需要調用另一個應用程式定義域裡的對象時會是什麼樣的?預設情況下.NET是不允許對象跨應用程式定義域訪問的,
不管是不是在同一個進程內。但是呢如果要訪問,也不是不行的,.NET提供了兩種資料傳遞方式,一種是值傳遞,一種是引用傳遞
4.1按值封送
當應用程式定義域A調用應用程式定義域B中的對象時,應用程式定義域B中的對象會被拷貝一個複製到應用程式定義域A,這時候兩個對象是不存在任何關係的,這種情況叫做按值封送 一般情況下都是使類型使用Serializable特性,支援序列化,通過序列化來達到按值封送的目的,在被呼叫者序列化,到調用方還原序列化。
4.2引用封送
這種情況就是當應用程式定義域A調用應用程式定義域B的對象時,應用程式定義域A獲得的是應用程式定義域B中對象的引用,
這個引用掛在哪裡呢?掛在應用程式定義域A的對象代理上,這種情況就叫引用封送 引用封送就比按值封送有意思多了,想要滿足可以引用封送的要求,則對象必須繼承自MarshalByRefObject,MarshalByRefObject類型給出的解釋就是 允許在支援遠端的應用程式中跨應用程式定義域邊界訪問對象,這樣作為它的子類同樣的也享受這樣的優待。在引用封送中會有兩種遠程對象啟用模式,這個內容在下一個篇幅中會有詳細的範例程式碼。
金源
出處:http://www.cnblogs.com/jin-yuan/
本文著作權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面