標籤:style blog http color io os 使用 ar for
.Net Remoting技術,我們可以將其看作是一種分散式處理方式。作為應用程式之間通訊的一種機制,.Net Remoting與MSMQ訊息佇列不同,它不支援離線離線訊息,另外只適合.Net平台間程式的通訊.從微軟的產品角度來看,可以說Remoting就是分布式組件DCOM的一種升級,它改善了很多功能,並極好的融合到.Net平台下。.NET Remoting 提供了一種允許對象通過應用程式定義域與另一對象進行互動的架構。這也正是我們使用Remoting的原因。為什麼呢?在Windows作業系統中,是將應用程式分離為單獨的進程。這個進程形成了應用程式代碼和資料周圍的一道邊界。如果不採用處理序間通訊IPC(Internet Process Connection)機制,則在一個進程中執行的代碼就不能訪問另一進程。這是一種作業系統對應用程式的保護機制。然而在某些情況下,我們需要跨過應用程式定義域,與另外的應用程式定義域進行通訊,即穿越邊界(參考MSDN)。
現在來介紹一下其中涉及到的幾個比較重要的概念:
1.通道(channel),
在.Net Remoting中是通過通道(channel)來實現兩個應用程式定義域之間對象的通訊的。首先,用戶端通過Remoting,訪問通道以獲得服務端對象,再通過代理解析為用戶端對象。這就提供一種可能性,即以服務的方式來發行伺服器對象。遠程對象代碼可以運行在伺服器上(如伺服器啟用的對象和用戶端啟用的對象),然後用戶端再通過Remoting串連伺服器,獲得該服務物件並通過序列化在用戶端運行。
通道(channel)有4種嚴格說,很多資料上說有2-3種.應該有4種.HttpChanel和TcpChanel.
(1)HttpChannel。在將遠程對象駐留在 ASP.NET 中時,可以使用此通道。此通道使用 HTTP 協議在用戶端和伺服器之間發送訊息。可以使用HTTP協議中的加密機制.需要主機名稱字和連接埠號碼.
(2)TcpChannel。在將遠程對象駐留在 作業系統服務或其他可執行檔中時,此通道使用 TCP 通訊端在用戶端和伺服器之間發送訊息。同樣需要提供主機名稱字和連接埠號碼.不提供任何內建的安全功能。
(3)IPCChanel,進程間通道,只使用同一個系統內,進程之見的通訊.不需要需要主機名稱字和連接埠號碼.
(4)自訂通道 。自訂的傳輸通道可以使用任何基本的傳輸協議UDP/SMTP/IPX/訊息排隊等機制進行通訊.使用者可以根據需要自訂方式協議,因此.Net Remoting相對其他機制更加的靈活。不提供任何內建的安全功能。
2.遠程對象(Obeject)
在Remoting中要傳遞的對象,設計者除了需要瞭解通道的類型和連接埠號碼之外,無需再瞭解資料包的格式。但必須注意的是,用戶端在擷取伺服器端對象時,並不是獲得實際的服務端對象,而是通過代理獲得它的引用。遠程對象要繼承自MarshalByRefObject類,這個可以使遠程對象在remoting應用通訊中使用,支援對象的跨域邊界訪問.
3.啟用方式
(1)伺服器端啟用,又叫做知名WellKnown方式,是因為伺服器應用程式在啟用物件執行個體之前會在一個眾所周知的統一資源識別項(URI)上來發布這個類型。然後該伺服器處理序會為此類型配置一個WellKnown對象,並根據指定的連接埠或地址來發布對象。伺服器端啟用又分為SingleTon模式和SingleCall模式兩種。SingleTon模式:此為有狀態模式。如果設定為SingleTon啟用方式,則Remoting將為所有用戶端建立同一個對象執行個體。SingleCall模式:SingleCall是一種無狀態模式。一旦設定為SingleCall模式,則當用戶端調用遠程對象的方法時, Remoting會為每一個用戶端建立一個遠程對象執行個體,至於對象執行個體的銷毀則是由GC自動管理的。
(2)用戶端啟用。與WellKnown模式不同, Remoting在啟用每個對象執行個體的時候,會給每個用戶端啟用的類型指派一個URI。用戶端啟用模式一旦獲得用戶端的請求,將為每一個用戶端都建立一個執行個體引用。SingleCall模式和用戶端啟用模式是有區別的:首先,對象執行個體建立的時間不一樣。用戶端啟用方式是客戶一旦發出調用的請求,就執行個體化;而SingleCall則是要等到調用對象方法時再建立。其次,SingleCall模式啟用的對象是無狀態的,對象生命期的管理是由GC管理的,而用戶端啟用的對象則有狀態,其生命週期可自訂。其三,兩種啟用模式在伺服器端和用戶端實現的方法不一樣。尤其是在用戶端,SingleCall模式是由 GetObject()來啟用,它調用對象預設的建構函式。而用戶端啟用模式,則通過CreateInstance()來啟用,它可以傳遞參數,所以可以調用自訂的建構函式來建立執行個體。(詳細參考MSDN)
(4)代理Proxy,用戶端訪問的不能直接存取遠程對象,它是通過代理來訪問代理上的方法.代理對象又分為透明代理和真實代理,區別是,在透明代理上,客戶通過Invoke調用的是遠程對象上真實代理的方法.然後把訊息再傳遞給通道.
好了,介紹到此我們也基本瞭解.Net Remoting相關的知識,下面我們來學習的是具體的編程實現部分.程式大體分為3個部分遠程對象/伺服器/可戶端.現在我們來分別實現.伺服器端要添加引用System.Runtime.Remoting的程式集.
1.遠程對象(RemoteOject),也就是我們遠程要訪問的對象.首先定義一個Class,繼承MarshalByRefObject,可以使用在remoting應用中,支援對象的跨域邊界訪問.具體代碼如下:
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace Model{ //建立遠程對象,繼承MarshalByRefObject,可以使用在remoting應用中,支援對象的跨域邊界訪問 public class MyRemoteObject : MarshalByRefObject//訪問遠程對象需要通過代理 { //實現加法功能的方法,這個遠程對象可以實現封裝商務邏輯或者資料訪問等操作 public int AddForTcpTest(int a, int b) { return a + b; } //實現減法功能,測試HTTP通道 public int MinusForHttpTest(int a, int b) { return a - b; } //實現乘法功能,測試Ipc通道 public int MultipleForIpcTest(int a, int b) { return a * b; } }}
2伺服器端,註冊通道,以便處理序間通訊,我們這裡註冊了三種通道,分別是HttpChanel/TcpChanel/IPCChanel.具體代碼如下:
using System;using System.Collections.Generic;using System.Linq;using System.Runtime.Remoting;using System.Runtime.Remoting.Channels;using System.Runtime.Remoting.Channels.Http;using System.Runtime.Remoting.Channels.Ipc;using System.Runtime.Remoting.Channels.Tcp;using System.Text;using System.Threading.Tasks;using Model;namespace NetRemoting{ class Program { static void Main(string[] args) { //建立三種通道 //建立Tcp通道,使用連接埠10001 TcpChannel chanTcp = new TcpChannel(10001); //建立Http通道,使用連接埠10002 HttpChannel chanHttp = new HttpChannel(10002); //建立Ipc通道,Ipc只適合約系統內進程的通訊,所以不需要設定連接埠和主機名稱 IpcChannel chanIpc = new IpcChannel("YXLTestIpc"); //註冊通道 //註冊TCP通道 ChannelServices.RegisterChannel(chanTcp); //註冊Http通道 ChannelServices.RegisterChannel(chanHttp); //註冊Ipc通道 ChannelServices.RegisterChannel(chanIpc); ////////////////////////////////////////列印通道///////////////////////////////////////////////// // 列印TCP通道的名稱. Console.WriteLine("The name of the TCPChannel is {0}.", chanTcp.ChannelName); // 列印TCP通道的優先順序. Console.WriteLine("The priority of the TCPChannel is {0}.", chanTcp.ChannelPriority); // 列印Http通道的名稱. Console.WriteLine("The name of the HttpChannel is {0}.", chanHttp.ChannelName); // 列印Http通道的優先順序. Console.WriteLine("The priority of the HttpChannel is {0}.", chanHttp.ChannelPriority); // 列印IPC通道的名稱. Console.WriteLine("The name of the IpcChannel is {0}.", chanIpc.ChannelName); // 列印IPC通道的優先順序. Console.WriteLine("The priority of the IpcChannel is {0}.", chanIpc.ChannelPriority); ///////////////////////////////////////////註冊對象///////////////////////////////////////////////// //註冊對象MyRemoteObject到Net Remoting運行庫 RemotingConfiguration.RegisterWellKnownServiceType(typeof(MyRemoteObject), "RemoteObject.MyRemoteObject", WellKnownObjectMode.Singleton); ///////////////////For Debug///////////////////////////////////////////////////////////////////////// Console.WriteLine("Press any key to exit!"); System.Console.ReadLine(); } } }
建立Tcp通道,使用連接埠10001, 建立Http通道,使用連接埠10002,建立IPC通道,使用連接埠10003,IPC只適合約系統內進程的通訊,所以不需要設定連接埠和主機名稱.然後調用ChannelServices類的靜態方法RegisterChannel進行註冊.最後一步註冊對象MyRemoteObject到Net Remoting運行庫,同時要先配置遠程通訊基礎架構.第2個參數是對象的URI,“RemoteObject.MyRemoteObject”,用戶端URL一定要和這個匹配,不然會出現尋找不到代理對象的異常.WellKnownObjectMode.Singleton);遠程對象啟用方式是單件啟用模式,每次調用共用一個對象,SingleCall啟用模式會在每次調用的時候產生一個新對象.
3用戶端是控制台程式(實際項目類型可以替換,這裡只是為了作為例子選擇控制台類型).設定檔進行的設定如下:
<configuration> <appSettings> <add key="ServiceURLTcp" value="tcp://localhost:10001/RemoteObject.MyRemoteObject"/> <add key="ServiceURLHttp" value="http://localhost:10002/RemoteObject.MyRemoteObject"/> <add key="ServiceURLIpc" value="ipc://YXLTestIpc/RemoteObject.MyRemoteObject"/> </appSettings> <system.runtime.remoting> </system.runtime.remoting></configuration>
using System;using System.Collections.Generic;using System.Configuration;using System.Linq;using System.Text;using System.Threading.Tasks;using Model;namespace NetRemotingClient{ class Program { [STAThread] static void Main(string[] args) { MyRemoteObject proxyObjectTcp = (MyRemoteObject)Activator.GetObject(typeof(MyRemoteObject), ConfigurationManager.AppSettings["ServiceURLTcp"]); //通過代理訪問對象的方法,輸出結果 Console.WriteLine("This call object by TcpChannel,100+200 = {0}", proxyObjectTcp.AddForTcpTest(100, 200)); MyRemoteObject proxyObjectHttp = (MyRemoteObject)Activator.GetObject(typeof(MyRemoteObject), ConfigurationManager.AppSettings["ServiceURLHttp"]); //通過代理訪問對象的方法,輸出結果 Console.WriteLine("This call object by HttpChannel,100-200 = {0}", proxyObjectHttp.MinusForHttpTest(100, 200)); MyRemoteObject proxyObjectIpc = (MyRemoteObject)Activator.GetObject(typeof(MyRemoteObject), ConfigurationManager.AppSettings["ServiceURLIpc"]); //通過代理訪問對象的方法,輸出結果 Console.WriteLine("This call object by TcpChannel,100*200 = {0}", proxyObjectIpc.MultipleForIpcTest(100, 200)); Console.ReadKey(); } }}
WCF分布式開發必備知識(2):.Net Remoting