MSMQ微軟訊息佇列詳解
一、引言
Windows Communication Foundation(WCF)是Microsoft為構建面向服務的應用程式而提供的統一模型,該服務模型提供了支援鬆散耦合和版本管理的序列化功能,並提供了與訊息佇列(MSMQ)、COM+、Asp.net Web服務、.NET Remoting等微軟現有的分散式系統技術。利用WCF平臺,開發人員可以很方便地構建面向服務的應用程式(SOA)。可以認為,WCF是對之前現有的分散式技術(指的是MSMQ、.NET Remoting和Web 服務等技術)的整合和擴充套件,既http://www.cppcns.com然這樣,我們就有必要首先了解下之前分散式技術,只有這樣才能更深刻地明白WCF所帶來的好處。今天就分享下MSMQ這種分散式技術。
二、MSMQ的介紹
MSMQ全稱是Microsoft Message Queue——微軟訊息佇列。它是一種非同步傳輸模式,可以在不同的應用之間實現相互通訊,相互通訊的應用可以分佈在同一臺機器上,也可以分佈於相連的網路空間中的任一位置。
2.1 MSMQ 工作原理
MSMQ的實現原理是:訊息的傳送者把自己想要傳送的資訊放入一個容器,然後把它儲存到一個系統公用空間的訊息佇列中,本地或異地的訊息接收程式再從該佇列中取出發給它的訊息進行處理。
訊息佇列是一個公用儲存空間,它可以存在於記憶體中或物理檔案中,因此,訊息以兩種方式傳送,即快遞方式和可恢復模式。它們的區別是訊息儲存位置的不同,快遞方式,為了訊息的快速傳遞,所以把訊息放置在記憶體中,而不放在物理磁碟上,以獲得較高的處理能力;而可恢復模式在傳送過程的每一步驟中,都把訊息寫入物理磁碟上,這樣當儲存訊息佇列的機器發生故障而重新啟動後,可以把傳送的訊息恢復到故障傳送之前的狀態,以獲得更好的訊息程式設計客棧
MSMQ中主要有兩個概念。
- 一個是訊息Message:Message是通訊雙方需要傳遞的訊息,它可以是文字、圖片、視訊等。訊息包含傳送和接收者的標識,只有指定的使用者才能取得訊息。
- 一個是佇列Queue:用來儲存訊息的儲存空間,MSMQ中主要包括以下幾種佇列型別:
- 公共佇列:在整個訊息佇列網路中複製,有可能由網路連線的所有站點訪問。路徑格式為:機器名稱\佇列名稱
- 專用佇列(或叫私有佇列):不在整個網路中釋出,它們僅在所駐留的本地計算機上可用,專用佇列只能由知道佇列的完整路徑名稱或標籤的應用程式訪問。路徑格式為:機器名稱\Private$\佇列名稱
- 日誌佇列:包含確認在給定“訊息佇列中傳送的訊息回執訊息”。路徑格式為:機器名稱\佇列名稱\Journal$
- 響應佇列:包含目標應用程式接收到訊息時返回給傳送應用程式的響應訊息,包括機器日誌佇列、機器死信佇列和機器事務死信佇列。
- 機器日誌佇列對應的格式為:機器名稱\Journal$;
- 機器死信佇列對應的格式為:機器名稱\Deadletter$;
- 機器通道死信佇列對應的格式為:機器名稱\XactDeadletter$。
2.2 佇列引用說明
當建立了一個MessageQueue例項之後,就應指明和哪個佇列進行通訊,在.NET中有3種訪問指定訊息佇列的方法:
- 使用路徑,訊息佇列的路徑被機器名和佇列名唯一確定,所以可以用訊息佇列路徑來指明使用的訊息佇列。
- 使用格式名(format name),它是由MSMQ在訊息佇列建立時生成的唯一標識,個使命不由使用者指定,而是由佇列管理者自動生成的GUID。
- 使用標識名(label),它是訊息佇列建立時由訊息管理者指定的帶有意義的名字。
三、訊息佇列的優缺點
採用訊息佇列的好處是:由於是非同步通訊,無論是傳送方還是接收方都不同等待對方返回成功訊息,就可以執行餘下的程式碼,大大提高了處理的能力;在資訊傳遞過程中,具有故障恢復能力;MSMQ的訊息傳遞機制使得通訊的雙方具有不同的物理平臺成為可能。
訊息佇列缺點是不適合Client需要Server端實時互動情況,大量請求時候,響應可能延遲。
四、利用MSMQ開發分散式應用
4.1 環境準備
要想在.NET平臺進行MSMQ的開發,需要安裝訊息佇列,你需要開啟控制面板->程式->開啟或關閉Windows功能,勾選訊息佇列服務所有選項,具體操作如下圖所示:
勾選完之後點選確定之後,可以在我的電腦->管理->服務和應用程式->訊息佇列 看到下面的圖:
看到上面這個圖代表你已經成功配置了MSMQ的開發環境,下面就可以使用Visual Studio 進行開發。注意,對特定型別佇列的操作程式碼,一定要成功安裝對應的佇列型別。
4.2 使用MSMQ開發分散式應用
首先,實現伺服器端。建立一個控制檯專案,新增System.Messaging引用,因為訊息佇列的類全部封裝在System.Messaging.dll程式集裡。具程式設計客棧體服務端的程式碼如下:
using System;
using System.Messaging;
namespace MSMQServer
{
class Program
{
static void Main(string[] args)
{
// 建立一個公共佇列,公共佇列只能建立在域環境裡
//if (!MessageQueue.Exists(@pfcsdEHzC".\LearningHardMSMQ")) // 判斷此路徑下是否已經有該佇列
//{
// using (MessageQueue mq = MessageQueue.Create(@".\LearningHardMSMQ"))
// {
// mq.Label = "LearningHardQueue"; // 設定佇列標籤
// Console.WriteLine("已經建立了一個公共佇列");
// Console.WriteLine("路徑為:{0}",mq.Path);
// Console.WriteLine("佇列名字為:{0}",mq.QueueName);
// mq.Send("MSMQ Message","Leaning Hard"); // 傳送訊息
// }
//}
//if (MessageQueue.Exists(@".\Private$\LearningHardMSMQ"))
//{
// 刪除訊息佇列
// MessageQueue.Delete(@".\Private$\LearningHardMSMQ");
//}
// 建立一個私有訊息佇列
if (!MessageQueue.Exists(@".\Private$\LearningHardMSMQ"))
{
using (MessageQueue mq = MessageQueue.Create(@".\Private$\LearningHardMSMQ"))
{
mq.Label = "LearningHardPrivateQueue";
Console.WriteLine("已經建立了一個私有佇列");
Console.WriteLine("路徑為:{0}",mq.Path);
Console.WriteLine("私有佇列名字為:{0}",mq.QueueName);
mq.Send("MSMQ Private Message","Leaning Hard"); // 傳送訊息
}
}
// 遍歷所有的公共訊息佇列
//foreach (MessageQueue mq in MessageQueue.GetPublicQueues())
//{
// mq.Send("Sending MSMQ public message" + DateTime.Now.ToLongDateString(),"Learning Hard");
// Console.WriteLine("Public Message is sent to {0}",mq.Path);
//}
if (MessageQueue.Exists(@".\Private$\LearningHardMSMQ"))
{
// 獲得私有訊息佇列
MessageQueue mq = new MessageQueue(@".\Private$\LearningHardMSMQ");
mq.Send("Sending MSMQ private message" + DateTime.Now.ToLongDateString(),"Leaning Hard");
Console.WriteLine("Private Message is sent to {0}",mq.Path);
}
Console.Read();
}
}
}
伺服器端程式碼需要注意的是,公共佇列只能在域環境中建立,由於我的個人電腦沒有加入域環境,所以不能建立公共佇列,從開始的訊息佇列的截圖也可以看出,在圖中並沒有安裝公共佇列。
實現完伺服器端之後,自然就是完成客戶端。MSMQ程式的原理主要是:伺服器端把訊息傳送到共享的訊息佇列中,然後,客戶端從這個共享的訊息佇列中取出訊息進行處理。具體客戶端的實現程式碼如下所示:
using System; using System.Messaging; // 需要新增System.Messaging引用 namespace MSMQClient { class Program { static void Main(string[] args) { if (MessageQueue.Exists(@".\Private$\LearningHardMSMQ")) { // 建立訊息佇列物件 using (MessageQueue mq = new MessageQueue(@".\Private$\LearningHardMSMQ")) { // 設定訊息佇列的格式化器 mq.Formatter = new XmlMessageFormatter(new string[] { "System.String" }); foreach (Message msg in mq.GetAllMessages()) { Console.WriteLine("Received Private Message is: {0}",msg.Body); } Message firstmsg = mq.Receive(); // 獲得訊息佇列中第一條訊息 Console.WriteLine("Received The first Private Message is: {0}",firstmsg.Body); } } Console.Read(); } } }
4.3 執行演示
經過上面步驟,我們已經完成了MSMQ分散式程式的實現了,下面看看如何執行該程式來檢視效果。
首先,自然要啟動伺服器,右鍵MSMQServer專案->除錯->啟動新例項來啟動伺服器,具體步驟如下圖所示:
執行成功之後,你將到伺服器傳送訊息成功的控制檯介面,效果圖如下所示:
接下來執行客戶端來從訊息佇列中取得訊息並顯示在控制檯中,採用和伺服器相同的方式來啟動客戶端,右鍵MSMQClient->除錯->啟動新例項,看到客戶端的效果如下圖所示:
從上圖可以看出,客戶端確實成功地取得了訊息佇列中的訊息。
以上MSMQ程式需要特別注意是:MessageQueue.Receive()是取出訊息佇列中佇列中的第一條訊息,並從訊息佇列中移除它(MSDN中文翻譯上是錯誤,MSDN寫的是不移除,而英文原文是移除),而實際結果也是移除的,如果你再執行一次客戶端時,你會發現訊息佇列中只有一條訊息,具體執行效果如下圖所示:
五、總結
到這裡,MSMQ的內容就分享結束, 其MSMQ的實現原理也非常簡單,一句話慨括就是伺服器把訊息放在一個公共的地方,這個地方叫做訊息佇列,而其他客戶端可以從這個地方取出訊息進行處理。下一章將分享.NET 平臺上另外一種分散式技術——.NET Remoting。
本文的示例程式碼檔案:MSMQSample。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。