MSMQ微軟消息隊(duì)列詳解
一、引言
Windows Communication Foundation(WCF)是Microsoft為構(gòu)建面向服務(wù)的應(yīng)用程序而提供的統(tǒng)一編程模型,該服務(wù)模型提供了支持松散耦合和版本管理的序列化功能,并提供了與消息隊(duì)列(MSMQ)、COM+、Asp.net Web服務(wù)、.NET Remoting等微軟現(xiàn)有的分布式系統(tǒng)技術(shù)。利用WCF平臺(tái),開發(fā)人員可以很方便地構(gòu)建面向服務(wù)的應(yīng)用程序(SOA)。可以認(rèn)為,WCF是對(duì)之前現(xiàn)有的分布式技術(shù)(指的是MSMQ、.NET Remoting和Web 服務(wù)等技術(shù))的集成和擴(kuò)展,既然這樣,我們就有必要首先了解下之前分布式技術(shù),只有這樣才能更深刻地明白WCF所帶來(lái)的好處。今天就分享下MSMQ這種分布式技術(shù)。
二、MSMQ的介紹
MSMQ全稱是Microsoft Message Queue——微軟消息隊(duì)列。它是一種異步傳輸模式,可以在不同的應(yīng)用之間實(shí)現(xiàn)相互通信,相互通信的應(yīng)用可以分布在同一臺(tái)機(jī)器上,也可以分布于相連的網(wǎng)絡(luò)空間中的任一位置。
2.1 MSMQ 工作原理
MSMQ的實(shí)現(xiàn)原理是:消息的發(fā)送者把自己想要發(fā)送的信息放入一個(gè)容器,然后把它保存到一個(gè)系統(tǒng)公用空間的消息隊(duì)列中,本地或異地的消息接收程序再?gòu)脑撽?duì)列中取出發(fā)給它的消息進(jìn)行處理。
消息隊(duì)列是一個(gè)公用存儲(chǔ)空間,它可以存在于內(nèi)存中或物理文件中,因此,消息以兩種方式發(fā)送,即快遞方式和可恢復(fù)模式。它們的區(qū)別是消息存儲(chǔ)位置的不同,快遞方式,為了消息的快速傳遞,所以把消息放置在內(nèi)存中,而不放在物理磁盤上,以獲得較高的處理能力;而可恢復(fù)模式在傳送過(guò)程的每一步驟中,都把消息寫入物理磁盤上,這樣當(dāng)保存消息隊(duì)列的機(jī)器發(fā)生故障而重新啟動(dòng)后,可以把發(fā)送的消息恢復(fù)到故障發(fā)送之前的狀態(tài),以獲得更好的消息恢復(fù)能力。消息隊(duì)列可以放在發(fā)送方、接收方所在的機(jī)器上,也可以單獨(dú)放置在另外一臺(tái)機(jī)器上。另外,采用消息隊(duì)列機(jī)制,發(fā)送方不必要擔(dān)心接收方是否啟動(dòng),是否發(fā)生故障等因素,只要消息成功發(fā)送出去,就可以認(rèn)為處理完成,而實(shí)際上對(duì)方可能甚至未開機(jī),或者實(shí)際消息傳遞到對(duì)方可能在第二天。MSMQ機(jī)制類似QQ消息傳遞機(jī)制。下圖演示了MSMQ的實(shí)現(xiàn)原理。
MSMQ中主要有兩個(gè)概念。
- 一個(gè)是消息Message:Message是通信雙方需要傳遞的消息,它可以是文本、圖片、視頻等。消息包含發(fā)送和接收者的標(biāo)識(shí),只有指定的用戶才能取得消息。
- 一個(gè)是隊(duì)列Queue:用來(lái)保存消息的存儲(chǔ)空間,MSMQ中主要包括以下幾種隊(duì)列類型:
- 公共隊(duì)列:在整個(gè)消息隊(duì)列網(wǎng)絡(luò)中復(fù)制,有可能由網(wǎng)絡(luò)連接的所有站點(diǎn)訪問(wèn)。路徑格式為:機(jī)器名稱\隊(duì)列名稱
- 專用隊(duì)列(或叫私有隊(duì)列):不在整個(gè)網(wǎng)絡(luò)中發(fā)布,它們僅在所駐留的本地計(jì)算機(jī)上可用,專用隊(duì)列只能由知道隊(duì)列的完整路徑名稱或標(biāo)簽的應(yīng)用程序訪問(wèn)。路徑格式為:機(jī)器名稱\Private$\隊(duì)列名稱
- 日志隊(duì)列:包含確認(rèn)在給定“消息隊(duì)列中發(fā)送的消息回執(zhí)消息”。路徑格式為:機(jī)器名稱\隊(duì)列名稱\Journal$
- 響應(yīng)隊(duì)列:包含目標(biāo)應(yīng)用程序接收到消息時(shí)返回給發(fā)送應(yīng)用程序的響應(yīng)消息,包括機(jī)器日志隊(duì)列、機(jī)器死信隊(duì)列和機(jī)器事務(wù)死信隊(duì)列。
- 機(jī)器日志隊(duì)列對(duì)應(yīng)的格式為:機(jī)器名稱\Journal$;
- 機(jī)器死信隊(duì)列對(duì)應(yīng)的格式為:機(jī)器名稱\Deadletter$;
- 機(jī)器信道死信隊(duì)列對(duì)應(yīng)的格式為:機(jī)器名稱\XactDeadletter$。
2.2 隊(duì)列引用說(shuō)明
當(dāng)創(chuàng)建了一個(gè)MessageQueue實(shí)例之后,就應(yīng)指明和哪個(gè)隊(duì)列進(jìn)行通信,在.NET中有3種訪問(wèn)指定消息隊(duì)列的方法:
- 使用路徑,消息隊(duì)列的路徑被機(jī)器名和隊(duì)列名唯一確定,所以可以用消息隊(duì)列路徑來(lái)指明使用的消息隊(duì)列。
- 使用格式名(format name),它是由MSMQ在消息隊(duì)列創(chuàng)建時(shí)生成的唯一標(biāo)識(shí),個(gè)使命不由用戶指定,而是由隊(duì)列管理者自動(dòng)生成的GUID。
- 使用標(biāo)識(shí)名(label),它是消息隊(duì)列創(chuàng)建時(shí)由消息管理者指定的帶有意義的名字。
三、消息隊(duì)列的優(yōu)缺點(diǎn)
采用消息隊(duì)列的好處是:由于是異步通信,無(wú)論是發(fā)送方還是接收方都不同等待對(duì)方返回成功消息,就可以執(zhí)行余下的代碼,大大提高了處理的能力;在信息傳遞過(guò)程中,具有故障恢復(fù)能力;MSMQ的消息傳遞機(jī)制使得通信的雙方具有不同的物理平臺(tái)成為可能。
消息隊(duì)列缺點(diǎn)是不適合Client需要Server端實(shí)時(shí)交互情況,大量請(qǐng)求時(shí)候,響應(yīng)可能延遲。
四、利用MSMQ開發(fā)分布式應(yīng)用
4.1 環(huán)境準(zhǔn)備
要想在.NET平臺(tái)進(jìn)行MSMQ的開發(fā),需要安裝消息隊(duì)列,你需要打開控制面板->程序->打開或關(guān)閉Windows功能,勾選消息隊(duì)列服務(wù)所有選項(xiàng),具體操作如下圖所示:
勾選完之后點(diǎn)擊確定之后,可以在我的電腦->管理->服務(wù)和應(yīng)用程序->消息隊(duì)列 看到下面的圖:
看到上面這個(gè)圖代表你已經(jīng)成功配置了MSMQ的開發(fā)環(huán)境,下面就可以使用Visual Studio 進(jìn)行開發(fā)。注意,對(duì)特定類型隊(duì)列的操作代碼,一定要成功安裝對(duì)應(yīng)的隊(duì)列類型。
4.2 使用MSMQ開發(fā)分布式應(yīng)用
首先,實(shí)現(xiàn)服務(wù)器端。創(chuàng)建一個(gè)控制臺(tái)項(xiàng)目,添加System.Messaging引用,因?yàn)橄㈥?duì)列的類全部封裝在System.Messaging.dll程序集里。具體服務(wù)端的代碼如下:
using System; using System.Messaging; namespace MSMQServer { class Program { static void Main(string[] args) { // 創(chuàng)建一個(gè)公共隊(duì)列,公共隊(duì)列只能創(chuàng)建在域環(huán)境里 //if (!MessageQueue.Exists(@".\LearningHardMSMQ")) // 判斷此路徑下是否已經(jīng)有該隊(duì)列 //{ // using (MessageQueue mq = MessageQueue.Create(@".\LearningHardMSMQ")) // { // mq.Label = "LearningHardQueue"; // 設(shè)置隊(duì)列標(biāo)簽 // Console.WriteLine("已經(jīng)創(chuàng)建了一個(gè)公共隊(duì)列"); // Console.WriteLine("路徑為:{0}", mq.Path); // Console.WriteLine("隊(duì)列名字為:{0}", mq.QueueName); // mq.Send("MSMQ Message", "Leaning Hard"); // 發(fā)送消息 // } //} //if (MessageQueue.Exists(@".\Private$\LearningHardMSMQ")) //{ // 刪除消息隊(duì)列 // MessageQueue.Delete(@".\Private$\LearningHardMSMQ"); //} // 創(chuàng)建一個(gè)私有消息隊(duì)列 if (!MessageQueue.Exists(@".\Private$\LearningHardMSMQ")) { using (MessageQueue mq = MessageQueue.Create(@".\Private$\LearningHardMSMQ")) { mq.Label = "LearningHardPrivateQueue"; Console.WriteLine("已經(jīng)創(chuàng)建了一個(gè)私有隊(duì)列"); Console.WriteLine("路徑為:{0}", mq.Path); Console.WriteLine("私有隊(duì)列名字為:{0}", mq.QueueName); mq.Send("MSMQ Private Message", "Leaning Hard"); // 發(fā)送消息 } } // 遍歷所有的公共消息隊(duì)列 //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")) { // 獲得私有消息隊(duì)列 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(); } } }
服務(wù)器端代碼需要注意的是,公共隊(duì)列只能在域環(huán)境中創(chuàng)建,由于我的個(gè)人電腦沒有加入域環(huán)境,所以不能創(chuàng)建公共隊(duì)列,從開始的消息隊(duì)列的截圖也可以看出,在圖中并沒有安裝公共隊(duì)列。
實(shí)現(xiàn)完服務(wù)器端之后,自然就是完成客戶端。MSMQ程序的原理主要是:服務(wù)器端把消息發(fā)送到共享的消息隊(duì)列中,然后,客戶端從這個(gè)共享的消息隊(duì)列中取出消息進(jìn)行處理。具體客戶端的實(shí)現(xiàn)代碼如下所示:
using System; using System.Messaging; // 需要添加System.Messaging引用 namespace MSMQClient { class Program { static void Main(string[] args) { if (MessageQueue.Exists(@".\Private$\LearningHardMSMQ")) { // 創(chuàng)建消息隊(duì)列對(duì)象 using (MessageQueue mq = new MessageQueue(@".\Private$\LearningHardMSMQ")) { // 設(shè)置消息隊(duì)列的格式化器 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(); // 獲得消息隊(duì)列中第一條消息 Console.WriteLine("Received The first Private Message is: {0}", firstmsg.Body); } } Console.Read(); } } }
4.3 運(yùn)行演示
經(jīng)過(guò)上面步驟,我們已經(jīng)完成了MSMQ分布式程序的實(shí)現(xiàn)了,下面看看如何運(yùn)行該程序來(lái)查看效果。
首先,自然要啟動(dòng)服務(wù)器,右鍵MSMQServer項(xiàng)目->調(diào)試->啟動(dòng)新實(shí)例來(lái)啟動(dòng)服務(wù)器,具體步驟如下圖所示:
運(yùn)行成功之后,你將到服務(wù)器發(fā)送消息成功的控制臺(tái)界面,效果圖如下所示:
接下來(lái)運(yùn)行客戶端來(lái)從消息隊(duì)列中取得消息并顯示在控制臺(tái)中,采用和服務(wù)器相同的方式來(lái)啟動(dòng)客戶端,右鍵MSMQClient->調(diào)試->啟動(dòng)新實(shí)例,看到客戶端的效果如下圖所示:
從上圖可以看出,客戶端確實(shí)成功地取得了消息隊(duì)列中的消息。
以上MSMQ程序需要特別注意是:MessageQueue.Receive()是取出消息隊(duì)列中隊(duì)列中的第一條消息,并從消息隊(duì)列中移除它(MSDN中文翻譯上是錯(cuò)誤,MSDN寫的是不移除,而英文原文是移除),而實(shí)際結(jié)果也是移除的,如果你再運(yùn)行一次客戶端時(shí),你會(huì)發(fā)現(xiàn)消息隊(duì)列中只有一條消息,具體運(yùn)行效果如下圖所示:
五、總結(jié)
到這里,MSMQ的內(nèi)容就分享結(jié)束, 其MSMQ的實(shí)現(xiàn)原理也非常簡(jiǎn)單,一句話慨括就是服務(wù)器把消息放在一個(gè)公共的地方,這個(gè)地方叫做消息隊(duì)列,而其他客戶端可以從這個(gè)地方取出消息進(jìn)行處理。下一章將分享.NET 平臺(tái)上另外一種分布式技術(shù)——.NET Remoting。
本文的示例代碼文件:MSMQSample。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
詳解ABP框架的參數(shù)有效性驗(yàn)證和權(quán)限驗(yàn)證
ABP框架是基于ASP.NET的Web開發(fā)框架(GitHub: https://github.com/aspnetboilerplate),在ASP.NET框架之上又添加了更強(qiáng)大的功能,這里我們就來(lái)詳解ABP框架的參數(shù)有效性驗(yàn)證和權(quán)限驗(yàn)證2016-06-06ASP.NET中CheckBoxList復(fù)選框列表控件詳細(xì)使用方法
本文主要介紹CheckBoxList幾種常見的用法,并做出范例演示供大家參考,希望對(duì)學(xué)習(xí)asp.net的朋友有所幫助。2016-04-04C#簡(jiǎn)單獲取屏幕鼠標(biāo)坐標(biāo)點(diǎn)顏色方法介紹
C#簡(jiǎn)單獲取屏幕鼠標(biāo)坐標(biāo)點(diǎn)顏色方法介紹;有需求的朋友可以參考下2012-11-11asp.net下SQLite(輕量級(jí)最佳數(shù)據(jù)庫(kù)) 原理分析和開發(fā)應(yīng)用
SQLite是一個(gè)開源的嵌入式關(guān)系數(shù)據(jù)庫(kù),它在2000年由D. Richard Hipp發(fā)布,它的減少應(yīng)用程序管理數(shù)據(jù)的開銷,SQLite可移植性好,很容易使用,很小,高效而且可靠2011-10-10解析ABP框架領(lǐng)域?qū)又械膶?shí)體類與倉(cāng)儲(chǔ)類
基于ASP.NET的ABP框架遵循DDD領(lǐng)域驅(qū)動(dòng)設(shè)計(jì),其中就有一個(gè)領(lǐng)域?qū)拥母拍?這里我們就來(lái)解析ABP框架領(lǐng)域?qū)又械膶?shí)體類與倉(cāng)儲(chǔ)類:2016-06-06