本帖透過 .NET 代碼和 Windows 的圖形界面,簡單測試 Windows Server 2008 R2 中的 MSMQ (Microsoft Message Queue)。
------------------------------------------------------------------------------
消息隊列 (也稱為 MQ),讓在不同時間運行的應用程序,可在異類網絡和可能暫時脫機的系統之間通訊。我們撰寫的應用程序,可向隊列發送消息,或從隊列讀取消息。
消息隊列提供了以下好處:
- 保證消息的傳遞
- 高效路由
- 增強的安全性
- 基于優先級的消息傳遞
------------------------------------------------------------------------------
與 Windows Server 2008 R2 / Windows 7 一起發布的 Message Queuing 5.0 中,引入了下列的新功能:
- 處理大量隊列的能力
Message Queuing 5.0 提供了處理大量隊列的能力。盡管 Message Queuing 4.0 未對可創建的隊列數目實行特定限制,但當有數千個隊列時,還是會對性能造成負面影響。特別是將隊列加載到內存中時,因隊列查找的算法,而大大增加了消息隊列服務的啟動時間。而對于 Windows Server 2008 R2、Windows 7,已對消息隊列在啟動時使用的隊列查找算法進行了優化,當系統上承載了大量隊列時,會顯著增加消息隊列的啟動性能。
- 更安全的身份驗證算法
Message Queuing 5.0 支持安全哈希算法 2.0 (SHA2),和 Windows Server 2008 R2 支持的所有高級哈希算法。默認設置為 SHA-2,摘要長度為 512 位。由于 SHA1、消息摘要版本 2 (MD2)、MD4、MD5 和消息驗證代碼 (MAC) 等算法,被認為不夠安全,因此默認情況下,對這些算法的支持在 Message Queuing 5.0 中處于禁用狀態。若要啟用不夠安全的算法,必須自行添加 WeakHashAlgorithms 注冊表項。
------------------------------------------------------------------------------
安裝消息隊列
執行用戶必須要有本地 Administrators 組中的成員身份,或等效身份。
在 Windows 7 上安裝消息隊列的步驟:
- 打開“控制面板”。
- 單擊“程序”,然后在“程序和功能”下,單擊“打開或關閉 Windows 功能”。
-或者-
單擊“經典視圖”,雙擊“程序和功能”,然后在任務窗格中單擊“打開或關閉 Windows 功能”。 - 依次展開“Microsoft Message Queue (MSMQ) 服務器”、“Microsoft Message Queue (MSMQ) 服務器核心”,然后選中要安裝的消息隊列功能的復選框。
- 單擊“確定”。
- 如果系統提示您重新啟動計算機,請單擊“確定”以完成安裝。
在 Windows Server 2008 R2 上安裝消息隊列的步驟:
- 單擊“開始”,依次指向“程序”、“管理工具”,然后單擊“服務器管理器”顯示服務器管理器。
- 單擊“添加功能”啟動“添加功能向導”。
- 依次展開 MSMQ、“MSMQ 服務”,然后選中要安裝的消息隊列功能的復選框。
- 單擊“下一步”,然后單擊“安裝”。
- 如果系統提示您重新啟動計算機,請單擊“確定”以完成安裝。

圖 1 安裝過程,以 Windows Server 2008 R2 為例

圖 2 安裝過程,以 Windows Server 2008 R2 為例
不同版本的 Windows 支持不同的消息隊列功能,下表列出了各版 Windows 7 和 Windows Server 2008 R2 所支持的功能:
| 功能 | Windows 7 簡易版 |
Windows 7 家庭普通版 |
Windows 7 家庭高級版 |
Windows 7 旗艦版 |
Windows 7 專業版 |
Windows 7 企業版 |
Windows Server 2008 R2 所有版本 |
|---|---|---|---|---|---|---|---|
|
Microsoft Message Queue (MSMQ) |
支持 |
支持 |
支持 |
支持 |
支持 |
支持 |
支持 |
|
消息隊列管理控制臺 |
支持 |
支持 |
支持 |
支持 |
支持 |
支持 |
支持 |
|
Microsoft Active Directory 域服務 |
不支持 |
不支持 |
不支持 |
支持 |
支持 |
支持 |
支持 |
|
MSMQ HTTP 支持/HTTP 支持 |
不支持 |
不支持 |
支持 |
支持 |
支持 |
支持 |
支持 |
|
MSMQ 觸發器/消息隊列觸發器 |
支持 |
支持 |
支持 |
支持 |
支持 |
支持 |
支持 |
|
MSMQ DCOM 代理/消息隊列 |
支持 |
支持 |
支持 |
支持 |
支持 |
支持 |
支持 |
|
多播支持/多播支持 |
支持 |
支持 |
支持 |
支持 |
支持 |
支持 |
支持 |
|
路由服務 |
不支持 |
不支持 |
不支持 |
不支持 |
不支持 |
不支持 |
支持 |
------------------------------------------------------------------------------
只允許隊列中經過驗證的消息
創建隊列時,默認的權限是每個人都可以向該隊列發送消息。若要獲取更高的安全性,可更改隊列的默認安全權限。也可以在創建隊列時指定隊列的屬性。例如,可以指定只接受經過身份驗證的消息。
以下為只允許在隊列中,放置經過身份驗證消息的步驟:
- 打開“計算機管理”。
- 在控制臺樹中,右鍵單擊隊列。
位置如下:
計算機管理/服務和應用程序/消息隊列/YourQueueFolder(如“公用隊列”或“專用隊列”)/YourQueue - 單擊“屬性”。
- 在“常規”選項卡上,選中“已驗證”復選框。

圖 3
------------------------------------------------------------------------------
創建和使用隊列
在 .NET 中,提供了方便我們操作 MSMQ 的 API - System.Messaging,而創建隊列可用其中的 MessageQueue.Create。
Create方法有兩個重載:
1、Message.Create(string path):創建非事務性隊列。
2、Message.Create(string path, bool transactional):指定創建事務性或者非事務性隊列。
在創建隊列時先判斷是否已經存在隊列,還有就是權限問題。
創建各種類別的隊列,是通過 path 屬性不同的表現來實現:
1、公用隊列:MachineName\QueueName
2、專用隊列:MachineName\Private$\QueueName
3、日記隊列:MachineName\QueueName\Journal$
4、計算機日記隊列:MachineName\Journal$
5、計算機死信隊列:MachineName\Deadletter$
6、計算機事務性死信隊列:MachineName\XactDeadletter$
完整測試代碼如下 (VS 2010 / ASP.NET 4.0 + Windows Server 2008 R2):
測試代碼
using System.Messaging;
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
//通過 Create 方法創建新的消息隊列
protected void Button1_Click(object sender, EventArgs e)
{
if (!MessageQueue.Exists(@".\private$\myQueue"))
{
using (MessageQueue mq = MessageQueue.Create(@".\private$\myQueue"))
{
Response.Write(mq.Label + "<br>");
Response.Write(mq.Path + "<br>");
Response.Write(mq.QueueName + "<br>");
Response.Write(mq.Authenticate + "<br>");
//在 MSMQ 中消息的大小,默認不能超過 4 MB
Response.Write(mq.MaximumQueueSize + "<br>");
}
}
else
{
Response.Write("myQueue已經存在!");
}
}
//發送消息到隊列
protected void Button2_Click(object sender, EventArgs e)
{
//連接到本地的隊列
MessageQueue myQueue = new MessageQueue(@".\private$\myQueue");
Message myMessage = new Message();
myMessage.Body = "「iPad」日本では4月後半発売"; //消息內容
myMessage.Formatter = new XmlMessageFormatter(new Type[] { typeof(string) });
//設置消息發送的優先級別
//myMessage.Priority = MessagePriority.Highest; //最高消息優先級
//發送消息到隊列中
myQueue.Send(myMessage);
myMessage.Dispose();
myQueue.Dispose();
}
//client-side: 從隊列中接收指定的消息
protected void Button3_Click(object sender, EventArgs e)
{
//連接到本地隊列
MessageQueue myQueue = new MessageQueue(@".\private$\myQueue");
myQueue.Formatter = new XmlMessageFormatter(new Type[] { typeof(string) });
Message myMessage = null;
try
{
//從隊列中接收消息
//Peek: 返回隊列中第一條消息的副本,而不從隊列中移除該消息
//Receive: 接收隊列中的第一條消息,但不將它從隊列中移除
//PeekById: 返回具有指定消息標識符的消息的副本,但不從隊列中移除消息
//ReceiveById: 接收匹配給定標識符的消息,并將其從隊列中移除
myMessage = myQueue.Peek();
string strContext = (string)myMessage.Body; //獲取消息的內容
Response.Write("消息內容為:" + strContext + "<br>");
}
catch // (MessageQueueException e)
{
Response.Write("error4");
}
finally
{
myMessage.Dispose();
myQueue.Dispose();
}
}
//獲取隊列的全部消息
protected void Button4_Click(object sender, EventArgs e)
{
MessageQueue myQueue = new MessageQueue(".\\private$\\myQueue");
//GetAllMessages: 得到隊列中的所有消息
Message[] myMessage = myQueue.GetAllMessages();
XmlMessageFormatter formatter = new XmlMessageFormatter(new Type[] { typeof(string) });
for (int i = 0; i < myMessage.Length; i++)
{
myMessage[i].Formatter = formatter;
Response.Write(myMessage[i].Body.ToString() + "<br>");
}
myQueue.Dispose();
}
//清空指定隊列的消息
protected void Button5_Click(object sender, EventArgs e)
{
MessageQueue myQueue = new MessageQueue(@".\private$\myQueue");
myQueue.Purge(); //刪除此隊列中包含的所有消息
//刪除服務器上的隊列
//MessageQueue.Delete(@".\private$\myQueue");
myQueue.Dispose();
}
}

圖 4 執行結果
------------------------------------------------------------------------------
事務性消息處理
在 MSMQ 中利用事務性處理,可以確保事務中的消息按照順序傳送,只傳送一次,并且從目的隊列成功地被檢索。
若要發送或接收消息時加入事務,可以使用 MessageQueueTransaction 類以創建事務,并將其傳遞到 MessageQueue.Send 方法或 MessageQueue.Receive 方法 [3]。
啟動了事務后的消息發送代碼:
myTransaction.Begin();
//發送消息到隊列中
myQueue.Send(myMessage, myTransaction);
myTransaction.Commit();
啟動了事務后的消息讀取代碼:
{
MessageQueueTransaction myTransaction = new MessageQueueTransaction();
myTransaction.Begin();
//從隊列中接收消息
Message myMessage = myQueue.Receive(myTransaction);
string context = myMessage.Body as string; //獲取消息的內容
myTransaction.Commit();
}
------------------------------------------------------------------------------
參考文章:
[1] 使用消息組件
http://msdn.microsoft.com/zh-cn/library/be74twsx.aspx
[2] MessageQueue 成員
http://msdn.microsoft.com/zh-cn/library/system.messaging.messagequeue_members.aspx
[3] MessageQueueTransaction 類
http://msdn.microsoft.com/zh-cn/library/system.messaging.messagequeuetransaction.aspx
[4] 博客園里數十篇文章
http://www.rzrgm.cn/beniao/archive/2008/06/26/1229934.html
http://www.rzrgm.cn/beniao/archive/2008/06/28/1230311.html
http://www.rzrgm.cn/frank_xl/archive/2009/02/09/1387125.html
http://www.rzrgm.cn/Henllyee/archive/2009/02/28/1400582.html
http://www.rzrgm.cn/jiekeng/articles/511303.html
http://www.rzrgm.cn/neozhu/category/18481.html
http://www.rzrgm.cn/rickie/category/13595.html
其他高手的文章...
------------------------------------------------------------------------------

浙公網安備 33010602011771號