.Net Remoting的雙向通信和Windows Service的宿主服務
原文:.Net Remoting的雙向通信和Windows Service的宿主服務
作為微軟分布式技術之一的.Net Remoting,從性能、安全等各方面來說都是相對比較穩定的,也是一項比較成熟的分布式技術。
從學習.Net Remoting至今,僅僅只使用了一次這門技術,是在去年的一個IM產品中。最近公司的產品出現了很多問題,服務器、通信接口、網站都陸續被攻擊(DDOS)。這對於做互聯網產業的同行來說就清楚這裏面的關系,強大的DDOS攻擊可以直接讓產品無法正常運營甚至停止運營。
經過一系列的分析,我打算使用.Net Remoting這門技術人為的通過編程開發的方式來解決上述的一些問題。其中.Net Remoting的雙向通信機制可以解決產品中的部門業務流程(比如在線充值,充值成功|失敗通知客戶端),從通信效率上來說也優於WEB應用接口(比如Alipay的支付接口)。基於Windows Service的宿主服務、或通過IIS來宿主Remoting的服務都是比較方便的。不過我放棄了基於IIS部署.Net Remoting,IIS部署的服務始終都無法逃避開DDOS的攻擊。 Windows Service相比之下更適合於防止DDOS攻擊。
現在有一個小的功能需求,我們要做一個聊天應用,要求使用.Net Remoting來提供遠程接口,當客戶端調用.Net Remoting遠程接口發送消息到服務器後,服務器對詳細進行一系列的處理(如在多人聊天的情況下廣播消息,一對一聊天的情況下傳遞消息到另一客戶端,其中還可能包括寫數據庫等多項操作),這裏為了方便演示我就將消息回發給自己。
好的,了解清楚了需求我們可以定義兩個接口,一個應用於發送消息的接口,一個應用於回發消息的接口,從某種角度(如WCF中)也可以叫契約。
1 namespace ChatRoom.Contract2 {
3 public interface IDuplexChat
4 {
5 void SendMessage(string message, IChatCallback callBack);
6 }
7 }
8 namespace ChatRoom.Contract
9 {
10 /// <summary>
11 /// 服務器端回調接口
12 /// </summary>
13 public interface IChatCallback
14 {
15 /// <summary>
16 /// 回調方法,顯示聊天消息
17 /// </summary>
18 /// <param name="message"></param>
19 void ShowMessage(string message);
20 }
21 }
接口定義好了,現在可以提供Remoting遠程服務了,既然是.Net Remoting遠程服務,那麽就必須繼承於MarshalByRefObject,同時我們還實現IDuplexChat接口,如下:
1 namespace ChatRoom.Remoting2 {
3 public class DuplexChatRemoting : MarshalByRefObject, IDuplexChat
4 {
5 public void SendMessage(string message, IChatCallback callBack)
6 {
7 Console.WriteLine("Invoke the method SendMessage()");
8
9 //do other
10 callBack.ShowMessage(message);
11 }
12 }
13 }
通常開發.Net Remoting程序都會有宿主、服務和客戶端三個基本的程序模塊。上面已經實現了Remoting服務,接下來就需要將該服務通過一種特定的方式來宿主(控制臺程序、IIS或Windows Service)服務,宿主服務也就是將遠程服務公布出來,並提供一種遠程連接的方式,通常也稱其為通道(信道)。鑒於程序的靈活性我們可通過配置文件的方式來配置.Net Remoting,比如我們通過控制臺程序來宿主服務,如下配置代碼塊:
1 <?xml version="1.0" encoding="utf-8" ?>2 <configuration>
3 <system.runtime.remoting>
4 <application name="ChatRoom">
5 <service>
6 <wellknown mode="SingleCall" type="ChatRoom.Remoting.DuplexChatRemoting,ChatRoom.Remoting" objectUri="ChatRoomURL"></wellknown>
7 </service>
8 <channels>
9 <channel ref="http" port="8080">
10 <serverProviders>
11 <provider ref="wsdl"></provider>
12 <formatter ref="binary" typeFilterLevel="Full"></formatter>
13 </serverProviders>
14 <clientProviders>
15 <formatter ref="binary"></formatter>
16 </clientProviders>
17 </channel>
18 </channels>
19 </application>
20 </system.runtime.remoting>
21 </configuration>
1 namespace ChatRoom.ConsoleHost
2 {
3 class Program
4 {
5 static void Main(string[] args)
6 {
7 RemotingConfiguration.Configure("ChatRoom.ConsoleHost.exe.config", false);
8 Console.WriteLine(".Net Remoting 服務已啟動");
9 Console.Read();
10 }
11 }
12 }
宿主和服務都提供好,現在我們需要一個調用客戶端,遠程服務已經通過宿主提供好了並定義好了通信信道。那麽客戶端也得遵守宿主裏提供的通信規則,既按照宿主裏提供的通信地址和端口進行通信。
Code
客戶端的調用示例程序代碼塊:
1 namespace ChatRoom.Client2 {
3 class Program
4 {
5 static IDuplexChat proxy = null;
6 static string message = string.Empty;
7
8 static void Main(string[] args)
9 {
10 RemotingConfiguration.Configure("ChatRoom.Client.exe.config", false);
11 proxy = (IDuplexChat)Activator.GetObject(typeof(IDuplexChat), "http://localhost:8080/ChatRoom/ChatRoomURL");
12
13 message = Console.ReadLine();
14 SendMessage(message);
15 }
16
17 private static void SendMessage(string message)
18 {
19 proxy.SendMessage(message, new ChatRoomCallBackHandler());
20
21 message = Console.ReadLine();
22 if (message != "exit")
23 {
24 SendMessage(message);
25 }
26 }
27 }
28 }
OK,如上便可完成一個雙向通信(Client---Server|Server---Client)的簡單應用。通過上面使用控制臺的方式來宿主.Net Remoting的遠程服務,如果不小心關閉了控制臺也就管理了遠程服務,每次使用遠程服務都需要先確保服務已經成功啟動,這是非常麻煩的事情。
我們可以通過Windows服務來避免不小心關閉遠程服務的缺點,建立Windows服務項目,直接將上面控制臺程序裏的配置文件復制到Windows服務項目裏,在默認的Server1的代碼文件下裝載.Net Remoting服務就OK:
1 protected override void OnStart(string[] args)2 {
3 RemotingConfiguration.Configure("ChatRoom.WinServiceHost.exe.config", false);
4 }
光這樣是不能完成Windows服務的開安並成功安裝,還需要一個安裝程序類來對Windows服務進行一些設置。詳細請查詢Windows服務開發相關的資料。
最後只需要將windows服務安裝到計算機上就OK。
本文示例代碼下載:ChatRoom.rar
.Net Remoting的雙向通信和Windows Service的宿主服務