利用 MSMQ(Microsoft Message Queue),應用程式開發人員可以通過發送和接收訊息方便地與應用程式進行快速可靠的通訊。訊息處理為您提供了有保障的訊息傳遞和執行許多業務處理的可靠的防故障方法。
MSMQ與XML Web Services和.Net Remoting一樣,是一種分布式開發技術。但是在使用XML Web Services或.Net Remoting組件時,Client端需要和Server端即時交換資訊,Server需要保持聯機。MSMQ則可以在Server離線的情況下工作,將Message臨時儲存在Client端的訊息佇列中,以後聯機時再發送到Server端處理。
顯然,MSMQ不適合於Client需要Server端及時響應的這種情況,MSMQ以非同步方式和Server端互動,不用擔心等待Server端的長時間處理過程。
雖然XML Web Services和.Net Remoting都提供了[OneWay]屬性來處理非同步呼叫,用來解決Server端長方法調用長時間阻礙Client端。但是不能解決大量Client負載的問題,此時Server接受的請求快於處理請求。
一般情況下,[OneWay]屬性不用於專門的Message Service中。
1. 基本術語和概念(Basic terms and concepts)
“訊息”是在兩台電腦間傳送的資料單位。訊息可以非常簡單,例如只包含文本字串;也可以更複雜,可能包含內嵌物件。
訊息被發送到隊列中。“訊息佇列”是在訊息的傳輸過程中儲存訊息的容器。訊息佇列管理器在將訊息從它的源中繼到它的目標時充當中間人。隊列的主要目的是提供路由並保證訊息的傳遞;如果發送訊息時接收者不可用,訊息佇列會保留訊息,直到可以成功地傳遞它。
“訊息佇列”是 Microsoft 的訊息處理技術,它在任何安裝了 Microsoft Windows 的電腦群組合中,為任何應用程式提供訊息處理和訊息佇列功能,無論這些電腦是否在同一個網路上或者是否同時聯機。
“訊息佇列網路”是能夠相互間來回傳送訊息的任何一組電腦。網路中的不同電腦在確保訊息順利處理的過程中扮演不同的角色。它們中有些提供路由資訊以確定如何發送訊息,有些儲存整個網路的重要訊息,而有些只是發送和接收訊息。
“訊息佇列”安裝期間,管理員確定哪些伺服器可以互相通訊,並設定特定伺服器的特殊角色。構成此“訊息佇列”網路的電腦稱為“網站”,它們之間通過“站台連結”相互串連。每個站台連結都有一個關聯的“開銷”,它由管理員確定,指示了經過此站台連結傳遞訊息的頻率。
“訊息佇列”管理員還在網路中設定一台或多台作為“路由伺服器”的電腦。路由伺服器查看各站台連結的開銷,確定經過多個網站傳遞訊息的最快和最有效方法,以此決定如何傳遞訊息。
2. 隊列類型(Queue Type)
有兩種主要的隊列類型:由您或網路中的其他使用者建立的隊列和系統隊列。
使用者建立的隊列可能是以下任何一種隊列:
“公用隊列”在整個“訊息佇列”網路中複製,並且有可能由網路連接的所有網站訪問。
“專用隊列”不在整個網路中發布。相反,它們僅在所駐留的本機電腦上可用。專用隊列只能由知道隊列的完整路徑名或標籤的應用程式訪問。
“管理隊列”包含確認在給定“訊息佇列”網路中發送的訊息回執的訊息。指定希望 MessageQueue 組件使用的管理隊列(如果有的話)。
“響應隊列”包含目標應用程式接收到訊息時返回給發送應用程式的響應訊息。指定希望 MessageQueue 組件使用的響應隊列(如果有的話)。
系統產生的隊列一般分為以下幾類:
“日記隊列”可選地儲存發送訊息的副本和從隊列中移除的訊息副本。每個“訊息佇列”用戶端上的單個日記佇列儲存體從該電腦發送的訊息副本。在伺服器上為每個隊列建立了一個單獨的日記隊列。此日記跟蹤從該隊列中移除的訊息。
“無效信件佇列”儲存無法傳遞或已到期的訊息的副本。如果到期或無法傳遞的訊息是異動訊息,則被儲存在一種特殊的無效信件佇列中,稱為“交易式無法傳送的信件佇列”。死信儲存在到期訊息所在的電腦上。有關逾時期限和到期訊息的更多資訊,請參見預設訊息屬性。
“報告隊列”包含指示訊息到達目標所經過的路由的訊息,還可以包含測試訊息。每台電腦上只能有一個報告隊列。
“專用系統隊列”是一系列儲存系統執行訊息處理操作所需的管理和通知訊息的專用隊列。
在應用程式中進行的大多數工作都涉及訪問公用隊列及其訊息。但是,根據應用程式的日記記錄、確認和其他特殊處理需要,在日常操作中很可能要使用幾種不同的系統隊列。
3. 同步和非同步通訊(Synchronous VS. Asynchronous Communication)
隊列通訊天生就是非同步,因為將訊息發送到隊列和從隊列中接收訊息是在不同的進程中完成的。另外,可以非同步執行接收操作,因為要接收訊息的人可以對任何給定的隊列調用 BeginReceive 方法,然後立即繼續其他任務而不用等待回覆。這與人們所瞭解的“同步通訊”截然不同。
在同步通訊中,請求的發送方在執行其他任務前,必須等待來自預定接收方的響應。發送方等待的時間完全取決於接收方處理請求和發送響應所用的時間。
4. 同訊息佇列互動(Interacting with Message Queues)
訊息處理和訊息為基於伺服器的應用程式組件之間的處理序間通訊提供了強大靈活的機制。同組件間的直接調用相比,它們具有若干優點,其中包括:
穩定性 — 組件失敗對訊息的影響程度遠遠小於組件間的直接調用,因為訊息儲存在隊列中並一直留在那裡,直到被適當地處理。訊息處理同交易處理相似,因為訊息處理是有保證的。
訊息優先順序 — 更緊急或更重要的訊息可在相對不重要的訊息之前接收,因此可以為關鍵的應用程式保證足夠的回應時間。
離線能力 — 發送訊息時,它們可被發送到暫存佇列中並一直留在那裡,直到被成功地傳遞。當因任何原因對所需隊列的訪問不可用時,使用者可以繼續執行操作。同時,其他動作可以繼續進行,如同訊息已經得到了處理一樣,這是因為網路連接恢複時訊息傳遞是有保證的。
異動訊息處理 — 將多個相關訊息耦合為單個事務,確保訊息按順序傳遞、只傳遞一次並且可以從它們的目標隊列中被成功地檢索。如果出現任何錯誤,將取消整個事務。
安全性 — MessageQueue 組件基於的訊息佇列技術使用 Windows 安全來保護存取控制,提供審核,並對組件發送和接收的訊息進行加密和驗證。
5. 在.Net環境下編寫簡單的Message Queue程式
(1)先安裝Message Queuing Services
通過Control Panel,“Add/Remove Programs” – “Add/Remove Windows Components”步驟安裝MSMQ。
MSMQ可以安裝為工作群組模式或域模式。如果安裝程式沒有找到一台運行提供目錄服務的訊息佇列的伺服器,則只可以安裝為工作群組模式,此電腦上的“訊息佇列”只支援建立專用隊列和建立與其他運行“訊息佇列”的電腦的直接連接。
(2)配置MSMQ
開啟Computer Management – Message Queuing,在Private Queues下建立MSMQDemo隊列
(3)編寫代碼-簡單示範MSMQ對象
MessageQueue 類是“訊息佇列”周圍的封裝。MessageQueue 類提供對“訊息佇列”隊列的引用。可以在MessageQueue 建構函式中指定一個串連到現有資源的路徑,或者可在伺服器上建立新隊列。在調用Send、Peek 或 Receive 之前,必須將 MessageQueue 類的新執行個體與某個現有隊列關聯。
MessageQueue 支援兩種類型的訊息檢索:同步和非同步。同步的 Peek 和 Receive 方法使進程線程用指定的間隔時間等待新訊息到達隊列。非同步 BeginPeek 和 BeginReceive 方法允許主應用程式任務在訊息到達隊列之前,在單獨的線程中繼續執行。這些方法通過使用回調對象和狀態物件進行工作,以便線上程之間進行資訊通訊。
// Send Message
private void btnSendMessage_Click(object sender, System.EventArgs e)
{
// Open queue
System.Messaging.MessageQueue queue = new System.Messaging.MessageQueue(".\\Private$\\MSMQDemo");
// Create message
System.Messaging.Message message = new System.Messaging.Message();
message.Body = txtMessage.Text.Trim();
message.Formatter = new System.Messaging.XmlMessageFormatter(new Type[] {typeof(string)});
// Put message into queue
queue.Send(message);
}
// Receive Message
private void btnReceiveMessage_Click(object sender, System.EventArgs e)
{
// Open queue
System.Messaging.MessageQueue queue = new System.Messaging.MessageQueue(".\\Private$\\MSMQDemo");
// Receive message, 同步的Receive方法阻塞當前執行線程,直到一個message可以得到
System.Messaging.Message message = queue.Receive();
message.Formatter = new System.Messaging.XmlMessageFormatter(new Type[] {typeof(string)});
txtReceiveMessage.Text = message.Body.ToString();
}