MSMQ消息隊列

message queue(微軟消息隊列)是在多個不一樣的應用之間實現相互通訊的一種異步傳輸模式,相互通訊的應用能夠分佈於同一臺機器上,也能夠分佈於相連的網絡空間中的任一位置。它的實現原理是:消息的發送者把本身想要發送的信息放入一個容器中(咱們稱之爲message),而後把它保存至一個系統公用空間的消息隊列(message queue)中;本地或者是異地的消息接收程序再從該隊列中取出發給它的消息進行處理。html

實質

  在消息傳遞機制中,有兩個比較重要的概念。一個是消息,一個是隊列。消息是由通訊的雙方所須要傳遞的信息,它能夠是各式各樣的媒體,如文本、聲音、圖象等等。消息最終的理解方式,爲消息傳遞的雙方事先商定,這樣作的好處是,一是至關於對數據進行了簡單的加密,二則採用本身定義的格式能夠節省通訊的傳遞量。消息能夠含有發送和接收者的標識,這樣只有指定的用戶才能看到只傳遞給他的信息和返回是否操做成功的回執。消息也能夠含有時間戳,以便於接收方對某些與時間相關的應用進行處理。消息還能夠含有到期時間,它代表若是在指定時間內消息還未到達則做廢,這主要應用與時間性關聯較爲緊密的應用。sql

  消息隊列是發送和接收消息的公用存儲空間,它能夠存在於內存中或者是物理文件中。消息能夠以兩種方式發送,即快遞方式(express)和可恢復模式(recoverable),它們的區別在於,快遞方式爲了消息的快速傳遞,把消息放置於內存中,而不放於物理磁盤上,以獲取較高的處理能力;可恢復模式在傳送過程的每一步驟中,都把消息寫入物理磁盤中,以獲得較好的故障恢復能力。消息隊列能夠放置在發送方、接收方所在的機器上,也能夠單獨放置在另一臺機器上。正是因爲消息隊列在放置方式上的靈活性,造成了消息傳送機制的可靠性。當保存消息隊列的機器發生故障而從新啓動之後,以可恢復模式發送的消息能夠恢復到故障發生以前的狀態,而以快遞方式發送的消息則丟失了。另外一方面,採用消息傳遞機制,發送方沒必要要再擔憂接收方是否啓動、是否發生故障等等非必要因素,只要消息成功發送出去,就能夠認爲處理完成,而實際上對方可能甚至不曾開機,或者實際完成交易時可能已是次日了。express

做用

  採用msmq帶來的好處是:因爲是異步通訊,不管是發送方仍是接收方都不用等待對方返回成功消息,就能夠執行餘下的代碼,於是大大地提升了事物處理的能力;當信息傳送過程當中,信息發送機制具備必定功能的故障恢復能力;msmq的消息傳遞機制使得消息通訊的雙方具備不一樣的物理平臺成爲可能。windows

  在微軟的.net平臺上利用其提供的msmq功能,能夠輕鬆建立或者刪除消息隊列、發送或者接收消息、甚至於對消息隊列進行管理。安全

1、Windows 7安裝、管理消息隊列
一、安裝消息隊列

   執行用戶必需要有本地 Administrators 組中的成員身份,或等效身份。
   具體步驟:
   開始—》控制面板—》程序—》程序和功能—》打開或關閉Windows功能—》依次展開Microsoft Message Queue (MSMQ) 服務器、Microsoft Message Queue (MSMQ) 服務器核心—》肯定
   若是系統提示您從新啓動計算機,請單擊「肯定」以完成安裝。
二、管理消息隊列
   計算機—》右鍵—》管理—》服務和應用程序—》消息隊列。
2、Windows Server 2008安裝、管理消息隊列
一、安裝消息隊列

   開始—》控制面板—》管理工具—》服務器管理器—》功能—》添加功能—》依次展開MSM、MSMQ服務—》肯定。
二、管理消息隊列
   計算機—》右鍵—》管理—》功能—》消息隊列。
3、建立、刪除和管理隊列
   要開發MSMQ程序就必須學習一個很重要的類(MessageQueue),該類位於名稱空間System.Messageing下。
經常使用方法:
   --Create()方法:建立使用指定路徑的新消息隊列。
   --Delete()方法:刪除現有的消息隊列。
   --Existe()方法:查看指定消息隊列是否存在。
   --GetAllMessages()方法:獲得隊列中的全部消息。
   --GetPublicQueues()方法:在「消息隊列」網絡中定位消息隊列。
   --Peek()/BeginPeek()方法:查看某個特定隊列中的消息隊列,但不從該隊列中移出消息。
   --Receive()/BeginReceive()方法:檢索指定消息隊列中最前面的消息並將其從該隊列中移除。
   --Send()方法:發送消息到指定的消息隊列。
   --Purge()方法:清空指定隊列的消息。
經常使用屬性:
   --Priority:設置消息優先級,MessagePriority枚舉裏所有進行了封裝,MessagePriority.High();
              AboveNormal:hight與Normal消息優先級之間;
              High:高級消息優先級;
              Highest:最高消息優先級;
              Low:低消息優先級;
              Lowest:最低消息優先級;
              Normal:普通消息優先級;
              VeryHigh:Highest和High消息優先級之間;
              VeryLow:Low和Lowest消息優先級之間;
4、發送和序列化消息
   MSMQ消息隊列中定義的消息由一個主體(body)和若干屬性構成。消息的主體能夠由文本、二進制構成,根據須要還能夠被加密。
   在MSMQ中消息的大小不可以超過4MB。發送消息是經過Send方法來完成的,須要一個Message參數。
一、發送消息:
   步驟:鏈接隊列-->指定消息格式-->提供要發送的數據(主體)-->調用Send()方法將消息發送出去。詳細見後面的示例程序。
二、序列化消息:
   消息序列化能夠經過.NET Framework附帶的三個預約義格式化程序來完成:
   --  XMLMessageFormatter對象----MessageQueue組件的默認格式化程序設置。
   --  BinaryMessageFormatter對象;
   --  ActiveXMessageFormatter對象;
   因爲後二者格式化後的消息一般不能爲人閱讀,因此咱們常常用到的是XMLMessageFormatter對象。該對象構造方法有三種重載:
   一、public XmlMessageFormatter();
   二、public XmlMessageFormatter(string[] targetTypeNames);
   三、public XmlMessageFormatter(Type[] targetTypes);
   如咱們後面的示例程序中用到的序列化語句:
   //序列化爲字符串
   XmlMessageFormatter formatter = new XmlMessageFormatter(new Type[] { typeof(string) });
5、讀取和接收消息
一、讀取消息:
   也就是從指定隊列中獲取消息。
二、接收消息有兩種方式:
   --> 經過Receive()方法。
   --> 經過Peek()方法。服務器

C# 添加引用System.Messaging,using System.Messaging;網絡

簡單的小例子異步

建立程序MSMQ1及MSMQ2jsp

using System;
using System.Messaging;
using System.Windows;

namespace MSMQ
{
    /// <summary>
    /// MainWindow.xaml 的交互邏輯
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            //新建消息循環隊列或鏈接到已有的消息隊列
            string path = ".\\private$\\killf";
            mq = MessageQueue.Exists(path) ? new MessageQueue(path) : MessageQueue.Create(path);
            mq.Formatter = new XmlMessageFormatter(new Type[] { typeof(string) });
        }

        private MessageQueue mq;

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            mq.Send(this.textBox1.Text);
        }
    }
}

MSMQ2async

using System;
using System.Messaging;
using System.Windows;

namespace MSMQ2
{
    /// <summary>
    /// MainWindow.xaml 的交互邏輯
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            //新建消息循環隊列或鏈接到已有的消息隊列
            string path = ".\\private$\\killf";
            mq = MessageQueue.Exists(path) ? new MessageQueue(path) : MessageQueue.Create(path);
            mq.Formatter = new XmlMessageFormatter(new Type[] { typeof(string) });
            mq.ReceiveCompleted += mq_ReceiveCompleted;
            mq.BeginReceive();
        }
        MessageQueue mq;

        void mq_ReceiveCompleted(object sender, ReceiveCompletedEventArgs e)
        {
            //throw new NotImplementedException();
            MessageQueue mq = (MessageQueue)sender;
            System.Messaging.Message m = mq.EndReceive(e.AsyncResult);
            //處理消息
            string str = m.Body.ToString();
            this.Dispatcher.Invoke(new Action<string>(ShowMsg), str);

            //繼續下一條消息
            mq.BeginReceive();
        }
        private void ShowMsg(string msg)
        {
            this.textBlock1.Text += msg + Environment.NewLine;
            return;
        }
    }
}

運行結果

截圖20160929112602880截圖20160929112555409

 

其餘前輩經驗

摘自 http://www.makaidong.com/%E5%8D%9A%E5%AE%A2%E5%9B%AD%E7%9F%A5%E8%AF%86%E5%BA%93/2779.shtml

發送:我的以爲發送問題比較重要的就是客戶端與遠程msmq服務器傳送msmq消息的問題,通過本人查資料發現遠程msmq通訊必須配置ad和開放對應權限,由於比較麻煩,並且本人所在項目自己沒跨網絡的需求,因此沒有深刻了解。其餘os tcp等內網方式通訊都ok, 不過還有一點值得注意的就是:與虛擬機的msmq通訊未能成功

     接收: 這裏先貼一下本人測試的接收代碼,這裏是客戶端發送和服務器接收分開作的測試,服務器接收端放到各類場景(虛擬機、外網、內網本機、內網其餘機器)測試

class program
    {
// define static class members.
static manualresetevent signal = new manualresetevent(false);
static int count = 0;
static void main(string[] args)
        {
string serverformatname = "formatname:direct=os:vis-pc\\private$\\msmqtest";
            console.writeline("msmq測試:");
try
            {
                messagequeue queue = new messagequeue(serverformatname,queueaccessmode.receive);
                queue.receivecompleted += new receivecompletedeventhandler(queue_receivecompleted);
                queue.beginreceive();
                signal.waitone();
            }
catch (messagequeueexception e)
            {
                console.writeline(e.tostring());
            }
return;
        }
//判斷成功接收後可更新隊列表狀態-須要隊列表提供接口
protected static void queue_receivecompleted(object source, receivecompletedeventargs e)
        {
try
            {
string result = string.empty;
if (source.equals(null))
                {
return;
                }        
                messagequeue mq = (messagequeue)source;
                message m = mq.endreceive(e.asyncresult);
//var query = m.body;
//result = (string)m.body;
                count += 1;
if (count == 10)
                {
                    signal.set();
                }
//可更新系統的隊列表狀態-證實信息接收成功
string filepath = @"e:\log.txt";
using (streamwriter sw = new streamwriter(filepath, true))
                {
                    string logmsg = string.format("[{0}]{1}", datetime.now.tostring(), "接收成功");
                    sw.writeline(logmsg);
                }
                mq.beginreceive();
            }
catch (messagequeueexception _mqe)
            {
                console.writeline(_mqe.tostring());
            }
return;
        }
    }

  這裏參考了微軟官方的示例,加了線程等待等,並且模擬了監聽功能,可是接收中出現了接收不到主體信息內容等(描述信息能收到),須要強調的是發送和接收在本機測試都沒問題 把接收程序放在其餘機器上會引起message對象boby屬性的:system.invalidoperationexception異常 經分析多是權限問題

  同事找到msdn上這樣一篇文章:啓用安全的遠程讀取 http://technet.microsoft.com/zh-cn/library/cc737783(ws.10).aspx 在這裏作過測試,可是未能成功,不知道是否是其餘權限沒有給足:馬開東博客也有人碰到過相似問題 http://www.cnblogs.com/yjmyzz/archive/2007/12/04/982440.html 和給出解決思路,這裏就不細說了。

     消息隊列是微軟對消息服務領域的開創性嘗試。它採用了特殊的通訊機制,對改善和提供系統的可擴展性和高可用性具備重要意義:

     (1)對異步的消息發送方式和離線通訊方式的支持

     (2)消息發送方和消息處理方能夠徹底分離

     (3)可靠的消息傳輸,消息隊列經過特殊的傳輸機制,好比消息確認、超時處理、消息日誌以及死信隊列等,從分保證了消息的可靠傳輸

     (4)事物的支持,提供對本地事物和分佈式事物的支持,能夠能夠把一個消息隊列的操做和一個基於sqlserver的操做歸入同一事物中

     消息隊列按照可訪問性可分爲兩種類型的隊列:

     (1)公共消息隊列,公共消息隊列發佈於活動目錄ad並被複制windows域。由於能夠在不知道隊列所在機器名稱的狀況下對公共隊列進行檢索,於是將公共隊列從一臺計算機移到另外一臺上,並不會對客戶端應用形成任何影響

     (2)私有消息隊列,私有消息隊列通常在沒有ad的工做組環境中使用,它們不支持身份驗證,而且須要隊列所在的計算機名稱方能定位

     最終拋棄了framework的msmq操做,使用wcf的msmq操做測試成功。wcf的可靠性會話是基於ws-rm標準的,而msmq只是ms自家的

     wcf下基於消息隊列的url具備net.msmq前綴。net.msmq地址中必需要指明隊列的類型

相關文章
相關標籤/搜索