1、引言
Windows Communication Foundation(WCF)是Microsoft爲構建面向服務的應用程序而提供的統一編程模型,該服務模型提供了支持鬆散耦合和版本管理的序列化功能,並提供了與消息隊列(MSMQ)、COM+、Asp.net Web服務、.NET Remoting等微軟現有的分佈式系統技術。利用WCF平臺,開發人員能夠很方便地構建面向服務的應用程序(SOA)。能夠認爲,WCF是對以前現有的分佈式技術(指的是MSMQ、.NET Remoting和Web 服務等技術)的集成和擴展,既然這樣,咱們就有必要首先了解下以前分佈式技術,只有這樣才能更深入地明白WCF所帶來的好處。今天就分享下MSMQ這種分佈式技術。html
2、MSMQ的介紹
MSMQ全稱是Microsoft Message Queue——微軟消息隊列。它是一種異步傳輸模式,能夠在不一樣的應用之間實現相互通訊,相互通訊的應用能夠分佈在同一臺機器上,也能夠分佈於相連的網絡空間中的任一位置。編程
2.1 MSMQ 工做原理
MSMQ的實現原理是:消息的發送者把本身想要發送的信息放入一個容器,而後把它保存到一個系統公用空間的消息隊列中,本地或異地的消息接收程序再從該隊列中取出發給它的消息進行處理。服務器
消息隊列是一個公用存儲空間,它能夠存在於內存中或物理文件中,所以,消息以兩種方式發送,即快遞方式和可恢復模式。它們的區別是消息存儲位置的不一樣,快遞方式,爲了消息的快速傳遞,因此把消息放置在內存中,而不放在物理磁盤上,以得到較高的處理能力;而可恢復模式在傳送過程的每一步驟中,都把消息寫入物理磁盤上,這樣當保存消息隊列的機器發生故障而從新啓動後,能夠把發送的消息恢復到故障發送以前的狀態,以得到更好的消息恢復能力。消息隊列能夠放在發送方、接收方所在的機器上,也能夠單獨放置在另一臺機器上。另外,採用消息隊列機制,發送方沒必要要擔憂接收方是否啓動,是否發生故障等因素,只要消息成功發送出去,就能夠認爲處理完成,而實際上對方可能甚至未開機,或者實際消息傳遞到對方可能在次日。MSMQ機制相似QQ消息傳遞機制。下圖演示了MSMQ的實現原理。網絡
MSMQ中主要有兩個概念。異步
- 一個是消息Message:Message是通訊雙方須要傳遞的消息,它能夠是文本、圖片、視頻等。消息包含發送和接收者的標識,只有指定的用戶才能取得消息。
- 一個是隊列Queue:用來保存消息的存儲空間,MSMQ中主要包括如下幾種隊列類型:
- 公共隊列:在整個消息隊列網絡中複製,有可能由網絡鏈接的全部站點訪問。路徑格式爲:機器名稱\隊列名稱
- 專用隊列(或叫私有隊列):不在整個網絡中發佈,它們僅在所駐留的本地計算機上可用,專用隊列只能由知道隊列的完整路徑名稱或標籤的應用程序訪問。路徑格式爲:機器名稱\Private$\隊列名稱
- 日誌隊列:包含確認在給定「消息隊列中發送的消息回執消息」。路徑格式爲:機器名稱\隊列名稱\Journal$ 響應隊列:包含目標應用程序接收到消息時返回給發送應用程序的響應消息,包括機器日誌隊列、機器死信隊列和機器事務死信隊列。
- 機器日誌隊列對應的格式爲:機器名稱\Journal$;
- 機器死信隊列對應的格式爲:機器名稱\Deadletter$;
- 機器信道死信隊列對應的格式爲:機器名稱\XactDeadletter$。
2.2 隊列引用說明
當建立了一個MessageQueue實例以後,就應指明和哪一個隊列進行通訊,在.NET中有3種訪問指定消息隊列的方法:分佈式
- 使用路徑,消息隊列的路徑被機器名和隊列名惟一肯定,因此能夠用消息隊列路徑來指明使用的消息隊列。
- 使用格式名(format name),它是由MSMQ在消息隊列建立時生成的惟一標識,個使命不禁用戶指定,而是由隊列管理者自動生成的GUID。
- 使用標識名(label),它是消息隊列建立時由消息管理者指定的帶有意義的名字。
3、消息隊列的優缺點
採用消息隊列的好處是:因爲是異步通訊,不管是發送方仍是接收方都不一樣等待對方返回成功消息,就能夠執行餘下的代碼,大大提升了處理的能力;在信息傳遞過程當中,具備故障恢復能力;MSMQ的消息傳遞機制使得通訊的雙方具備不一樣的物理平臺成爲可能。post
消息隊列缺點是不適合Client須要Server端實時交互狀況,大量請求時候,響應可能延遲。url
4、利用MSMQ開發分佈式應用
4.1 環境準備
要想在.NET平臺進行MSMQ的開發,須要安裝消息隊列,你須要打開控制面板->程序->打開或關閉Windows功能,勾選消息隊列服務全部選項,具體操做以下圖所示:spa
勾選完以後點擊肯定以後,能夠在個人電腦->管理->服務和應用程序->消息隊列 看到下面的圖:.net
看到上面這個圖表明你已經成功配置了MSMQ的開發環境,下面就可使用Visual Studio 進行開發。注意,對特定類型隊列的操做代碼,必定要成功安裝對應的隊列類型。
4.2 使用MSMQ開發分佈式應用
首先,實現服務器端。建立一個控制檯項目,添加System.Messaging引用,由於消息隊列的類所有封裝在System.Messaging.dll程序集裏。具體服務端的代碼以下:
1 using System; 2 using System.Messaging; 3 4 namespace MSMQServer 5 { 6 class Program 7 { 8 static void Main(string[] args) 9 { 10 // 建立一個公共隊列,公共隊列只能建立在域環境裏 11 //if (!MessageQueue.Exists(@".\LearningHardMSMQ")) // 判斷此路徑下是否已經有該隊列 12 //{ 13 // using (MessageQueue mq = MessageQueue.Create(@".\LearningHardMSMQ")) 14 // { 15 // mq.Label = "LearningHardQueue"; // 設置隊列標籤 16 // Console.WriteLine("已經建立了一個公共隊列"); 17 // Console.WriteLine("路徑爲:{0}", mq.Path); 18 // Console.WriteLine("隊列名字爲:{0}", mq.QueueName); 19 // mq.Send("MSMQ Message", "Leaning Hard"); // 發送消息 20 // } 21 //} 22 23 //if (MessageQueue.Exists(@".\Private$\LearningHardMSMQ")) 24 //{ 25 // 刪除消息隊列 26 // MessageQueue.Delete(@".\Private$\LearningHardMSMQ"); 27 //} 28 // 建立一個私有消息隊列 29 if (!MessageQueue.Exists(@".\Private$\LearningHardMSMQ")) 30 { 31 using (MessageQueue mq = MessageQueue.Create(@".\Private$\LearningHardMSMQ")) 32 { 33 mq.Label = "LearningHardPrivateQueue"; 34 Console.WriteLine("已經建立了一個私有隊列"); 35 Console.WriteLine("路徑爲:{0}", mq.Path); 36 Console.WriteLine("私有隊列名字爲:{0}", mq.QueueName); 37 mq.Send("MSMQ Private Message", "Leaning Hard"); // 發送消息 38 } 39 } 40 41 // 遍歷全部的公共消息隊列 42 //foreach (MessageQueue mq in MessageQueue.GetPublicQueues()) 43 //{ 44 // mq.Send("Sending MSMQ public message" + DateTime.Now.ToLongDateString(), "Learning Hard"); 45 // Console.WriteLine("Public Message is sent to {0}", mq.Path); 46 //} 47 48 if (MessageQueue.Exists(@".\Private$\LearningHardMSMQ")) 49 { 50 // 得到私有消息隊列 51 MessageQueue mq = new MessageQueue(@".\Private$\LearningHardMSMQ"); 52 mq.Send("Sending MSMQ private message" + DateTime.Now.ToLongDateString(), "Leaning Hard"); 53 Console.WriteLine("Private Message is sent to {0}", mq.Path); 54 } 55 56 Console.Read(); 57 } 58 } 59 }
服務器端代碼須要注意的是,公共隊列只能在域環境中建立,因爲個人我的電腦沒有加入域環境,因此不能建立公共隊列,從開始的消息隊列的截圖也能夠看出,在圖中並無安裝公共隊列。
實現完服務器端以後,天然就是完成客戶端。MSMQ程序的原理主要是:服務器端把消息發送到共享的消息隊列中,而後,客戶端從這個共享的消息隊列中取出消息進行處理。具體客戶端的實現代碼以下所示:
1 using System; 2 using System.Messaging; // 須要添加System.Messaging引用 3 4 namespace MSMQClient 5 { 6 class Program 7 { 8 static void Main(string[] args) 9 { 10 if (MessageQueue.Exists(@".\Private$\LearningHardMSMQ")) 11 { 12 // 建立消息隊列對象 13 using (MessageQueue mq = new MessageQueue(@".\Private$\LearningHardMSMQ")) 14 { 15 // 設置消息隊列的格式化器 16 mq.Formatter = new XmlMessageFormatter(new string[] { "System.String" }); 17 foreach (Message msg in mq.GetAllMessages()) 18 { 19 Console.WriteLine("Received Private Message is: {0}", msg.Body); 20 } 21 22 Message firstmsg = mq.Receive(); // 得到消息隊列中第一條消息 23 Console.WriteLine("Received The first Private Message is: {0}", firstmsg.Body); 24 } 25 } 26 Console.Read(); 27 } 28 } 29 }
4.3 運行演示
通過上面步驟,咱們已經完成了MSMQ分佈式程序的實現了,下面看看如何運行該程序來查看效果。
首先,天然要啓動服務器,右鍵MSMQServer項目->調試->啓動新實例來啓動服務器,具體步驟以下圖所示:
運行成功以後,你將到服務器發送消息成功的控制檯界面,效果圖以下所示:
接下來運行客戶端來從消息隊列中取得消息並顯示在控制檯中,採用和服務器相同的方式來啓動客戶端,右鍵MSMQClient->調試->啓動新實例,看到客戶端的效果以下圖所示:
從上圖能夠看出,客戶端確實成功地取得了消息隊列中的消息。
以上MSMQ程序須要特別注意是:MessageQueue.Receive()是取出消息隊列中隊列中的第一條消息,並從消息隊列中移除它(MSDN中文翻譯上是錯誤,MSDN寫的是不移除,而英文原文是移除),而實際結果也是移除的,若是你再運行一次客戶端時,你會發現消息隊列中只有一條消息,具體運行效果以下圖所示:
5、總結
到這裏,MSMQ的內容就分享結束, 其MSMQ的實現原理也很是簡單,一句話慨括就是服務器把消息放在一個公共的地方,這個地方叫作消息隊列,而其餘客戶端能夠從這個地方取出消息進行處理。下一章將分享.NET 平臺上另一種分佈式技術——.NET Remoting。
本文的示例代碼文件:MSMQSample。