Remoting服務端和客戶端程式該這樣模式來寫
伺服器啟用的物件是其生存期由伺服器直接控制的物件。伺服器應用程式域只有在客戶端在物件上進行方法呼叫時才建立這些物件,而不會在客戶端呼叫 new 或 Activator.GetObject 時建立這些物件;這節省了僅為建立例項而進行的一次網路往返過程。客戶端請求伺服器啟用的型別例項時,只在客戶端應用程式域中建立一個代理。然而,這也意味著當您使用預設實現時,只允許對伺服器啟用的型別使用預設建構函式。若要釋出其例項將使用帶引數的特定建構函式建立的型別,可以使用客戶端啟用或者動態地釋出您的特定例項。
伺服器啟用的物件有兩種啟用模式(或 WellKnownObjectMode 值):Singleton 和 SingleCall。
Singleton 型別任何時候都不會同時具有多個例項。如果存在例項,所有客戶端請求都由該例項提供服務。如果不存在例項,伺服器將建立一個例項,而所有後繼的客戶端請求都將由該例項來提供服務。由於 Singleton 型別具有關聯的預設生存期,即使任何時候都不會有一個以上的可用例項,客戶端也不會總接收到對可遠端處理的類的同一例項的引用。
SingleCall 遠端伺服器型別總是為每個客戶端請求設定一個例項。下一個方法呼叫將改由其他例項進行服務。從設計角度看,SingleCall 型別提供的功能非常簡單。這種機制不提供狀態管理,如果您需要狀態管理,這將是一個不利之處;如果您不需要,這種機制將非常理想。也許您只關心負載平衡和可伸縮性而不關心狀態,那麼在這種情況下,這種模式將是您理想的選擇,因為對於每個請求都只有一個例項。如果願意,開發人員可以向 SingleCall 物件提供自己的狀態管理,但這種狀態資料不會駐留在物件中,因為每次呼叫新的方法時都將例項化一個新的物件標識。
首先對於服務端啟用的兩種模式來做一個試驗,我們把遠端物件做如下的修改:
namespace RemoteObject
{
public class MyObject:MarshalByRefObject
{
private int i=0;
public int Add(int a,int b)
{
return a+b;
}
public int Count()
{
return ++i;
}
}
}
對客戶端做以下修改:
Console.WriteLine(app.Count());
Console.ReadLine();
第一次開啟客戶端的時候顯示1,第二次開啟的時候顯示2,類推……由此驗證了Singleton 型別任何時候都不會同時具有多個例項。如果存在例項,所有客戶端請求都由該例項提供服務。如果不存在例項,伺服器將建立一個例項,而所有後繼的客戶端請求都將由該例項來提供服務。
把伺服器端的config修改一下:
mode="SingleCall" />
(這裡注意大小寫,大寫的C)
再重新執行服務端和客戶端,開啟多個客戶端發現始終顯示1。由此驗證了SingleCall 型別對於每個客戶端請求都會重新建立例項。下一個方法呼叫將由另一個伺服器例項提供服務。
下面再說一下客戶端的啟用模式,msdn中這麼寫:
客戶端啟用的物件是其生存期由呼叫應用程式域控制的物件,正如物件對於客戶端是本地物件時物件的生存期由呼叫應用程式域控制一樣。對於客戶端啟用,當客戶端試圖建立伺服器物件的例項時發生一個到伺服器的往返過程,而客戶端代理是使用物件引用 (ObjRef) 建立的,該物件引用是從在伺服器上建立遠端物件返回時獲取的。每當客戶端建立客戶端啟用的型別的例項時,該例項都將只服務於該特定客戶端中的特定引用,直到其租約到期並回收其記憶體為止。如果呼叫應用程式域建立兩個遠端型別的新例項,每個客戶端引用都將只呼叫從其中返回引用的伺服器應用程式域中的特定例項。
理解一下,可以歸納出
1、客戶端啟用的時間是在客戶端請求的時候,而服務端啟用遠端物件的時間是在呼叫物件方法的時候
遠端物件修改如下:
namespace RemoteObject
{
public class MyObject:MarshalByRefObject
{
private int i=0;
public MyObject()
{
Console.WriteLine("啟用");
}
public int Add(int a,int b)
{
return a+b;
}
public int Count()
{
return ++i;
}
}
}
服務端配置檔案:
<system.runtime.remoting>
<application name="RemoteServer">
<service>
<activated type="RemoteObject.MyObject,RemoteObject"/>
</service>
<channels>
<channel ref="tcp" port="9999"/>
</channels>
</application>
</system.runtime.remoting>
</configuration>
客戶端程式:
namespace RemoteClient
{
class MyClient
{
[STAThread]
static void Main(string[] args)
{
//RemoteObject.MyObject app = (RemoteObject.MyObject)Activator.GetObject(typeof(RemoteObject.MyObject),System.Configuration.ConfigurationSettings.AppSettings["ServiceURL"]);
RemoteObject.MyObject app=(RemoteObject.MyObject)Activator.CreateInstance(typeof(RemoteObject.MyObject),null,new object[]{new System.Runtime.Remoting.Activation.UrlAttribute(System.Configuration.ConfigurationSettings.AppSettings["ServiceURL"])});
//Console.WriteLine(app.Count());
Console.ReadLine();
}
}
}
客戶端配置檔案:
<appSettings>
<add key="ServiceURL" value="tcp://localhost:9999/RemoteServer"/>
</appSettings>
</configuration>
(這裡的uri按照服務端配置檔案中application元素定義的RemoteServer來寫)
執行程式可以看到,在客戶端啟動的時候服務端就輸出了“啟用”,我們再轉回知名模式進行測試發現只有執行了方法才會在服務端輸出“啟用”。
2、客戶端啟用可以呼叫自定義的構造方法,而不像服務端啟用只能使用預設的構造方法
把客戶端程式碼修改如下:
Console.WriteLine(app.Count());
這裡看到我們在CreateInstance方法的第二個引數中提供了10作為構造方法的引數。在服務端啟用模式我們不能這麼做。
遠端物件構造方法修改如下:
{
this.i=k;
Console.WriteLine("啟用");
}
毫無疑問,我們執行客戶端發現輸出的是11而不是1了。
3、通過上面的例子,我們執行多個客戶端發現出現的永遠是11,因此,客戶端啟用模式一旦獲得客戶端的請求,將為每一個客戶端都建立一個例項引用。
總結:
1、Remoting支援兩種遠端物件:知名的和客戶啟用的。知名的遠端物件使用了uri作為標識,客戶程式使用這個uri來訪問那些遠端物件,也正式為什麼稱作知名的原因。對知名的物件來說2種使用模式:SingleCall和Singleton,對於前者每次呼叫都會新建物件,因此物件是無狀態的。對於後者,物件只被建立一次,所有客戶共享物件狀態,因此物件是有狀態的。另外一種客戶端啟用物件使用類的型別來啟用,uri再後臺被動態建立,並且返回給客戶程式。客戶啟用物件是有狀態的。
2、對於Singleton物件來說需要考慮伸縮性,Singleton物件不能在多個伺服器上被部署,如果要跨伺服器就不能使用Singleton了。
備註:個人習慣原因,在我的例子中服務端的配置都是用config檔案的,客戶端的配置都是基本用程式方式的
使用配置檔案的優點:無需重新編譯就可以配置通道和遠端物件,編寫的程式碼量比較少
使用程式定製的優點:可以獲得執行期間的資訊,對程式除錯有利。
附:msdn有關章節:
http://msdn.microsoft.com/library/CHS/cpguide/html/cpconActivation.asp
相關文章
- .Net Remoting服務端與客戶端呼叫示例REM服務端客戶端
- 客戶端,服務端客戶端服務端
- 服務端,客戶端服務端客戶端
- 服務端渲染和客戶端渲染服務端客戶端
- golang實現tcp客戶端服務端程式GolangTCP客戶端服務端
- python建立tcp服務端和客戶端PythonTCP服務端客戶端
- MQTT伺服器搭建服務端和客戶端MQQT伺服器服務端客戶端
- TCP程式設計之服務端和客戶端的開發TCP程式設計服務端客戶端
- 模板,從服務端到客戶端服務端客戶端
- 使用Apollo Server搭建GraphQL的服務端和客戶端Server服務端客戶端
- Eureka高可用叢集服務端和客戶端配置服務端客戶端
- 服務端和客戶端 RESTful 介面上傳 Excel 的 Python 程式碼服務端客戶端RESTExcelPython
- 「iOS」行車服務app 「客戶端、後端思路+程式碼」iOSAPP客戶端後端
- Java服務端和客戶端開發輔助工具UtilsJava服務端客戶端
- ZooKeeper服務發現客戶端客戶端
- OSSEC服務端配置客戶端批次部署方案服務端客戶端
- 001 Rust 網路程式設計,實現 TCP 服務端和客戶端程式Rust程式設計TCP服務端客戶端
- macOS 自帶的ftp服務端&vnc客戶端MacFTP服務端VNC客戶端
- Rest Post示例(java服務端、python客戶端)RESTJava服務端Python客戶端
- Android實現Thrift服務端與客戶端Android服務端客戶端
- rsync備份【基於客戶端與服務端】客戶端服務端
- 使用多種客戶端消費WCF RestFul服務(一)——服務端客戶端REST服務端
- PC客戶端安全測試服務客戶端
- HTML轉PDF的純客戶端和純服務端實現方案HTML客戶端服務端
- 對比分析--淺析SSR(服務端渲染)和SPA(客戶端渲染)服務端客戶端
- 淘淘商城系列——訂單系統服務端和客戶端工程搭建服務端客戶端
- SSLSocket實現服務端和客戶端雙向認證的例子服務端客戶端
- TCP協議服務端和客戶端的連線與通訊TCP協議服務端客戶端
- 服務端渲染vs客戶端渲染到前後端同構服務端客戶端後端
- 服務端如何獲取客戶端請求IP地址服務端客戶端
- 實現客戶端與服務端的HTTP通訊客戶端服務端HTTP
- MQTT協議從服務端到客戶端詳解MQQT協議服務端客戶端
- 客戶端與服務端Socket通訊原理詳解客戶端服務端
- 微服務架構,客戶端如何catch服務端的異常?微服務架構客戶端服務端
- 基於c語言的TCP客戶端、服務端基礎程式碼C語言TCP客戶端服務端
- Netty入門系列(1) --使用Netty搭建服務端和客戶端Netty服務端客戶端
- netty服務端監聽客戶端連線加入和斷開事件Netty服務端客戶端事件
- Qt實現網路聊天室(客戶端,服務端)QT客戶端服務端