C#基礎教程(三) 消息隊列——MSMQ

Net使用消息隊列,藉助windows組件來存儲要完成的一系列任務,不用程序使用同一個隊列,方便不同程序之間的數據共享和協作。

隊列分事務性隊列和非事務性隊列,默認創建的是非事務性隊列。那麼什麼是事務性隊列呢?事務性隊列將消息保存在磁盤上,實現了持久化,也就是說當我們關機,斷電後,下次再啓動機器,我們的消息依然保存在隊列裏面,而非事務性隊列則將消息保存在內存中,也就是說我重啓電腦後,隊列裏面的消息將不存在了。

(一) 複雜消息收發(對象)

static void Main(string[] args)
{
    const string queueName = @".\Private$\jiyiqin";
    MessageQueue mq = null;
    if (!MessageQueue.Exists(queueName))// 如果指定的路徑queueName中不存在隊列,那麼在該路徑,即queueName中創建一個消息隊列。jiyiqin就是你想要創建消息隊列的名字
    {
        mq = MessageQueue.Create(queueName);//創建名稱jiyiqin的消息隊列的實例。
        Console.WriteLine("創建消息隊列完成:" + queueName);
    }
    else  //如果消息隊列jiyiqin已經存在,那麼創建該消息隊列的一個實例
    {
        mq = new MessageQueue(queueName);//創建名稱jiyiqin的消息隊列的實例。
    }
    mq.SetPermissions("Administrator", MessageQueueAccessRights.FullControl);
    mq.SetPermissions("ANONYMOUS LOGON", MessageQueueAccessRights.FullControl);
    mq.SetPermissions("Everyone", MessageQueueAccessRights.FullControl);

    Message msgTx = new Message();
    msgTx.Formatter = new XmlMessageFormatter(new Type[] { typeof(MsgModel) });
    msgTx.Body = new MsgModel("1", "消息1");

    mq.Send(msgTx);
    Console.Write("成功發送消息," + DateTime.Now + "");

    if (mq.GetAllMessages().Length > 0)
    {
        System.Messaging.Message message = mq.Receive(TimeSpan.FromSeconds(5));
        if (message != null)
        {
            message.Formatter = new System.Messaging.XmlMessageFormatter(new Type[] { typeof(MsgModel) });//消息類型轉換
            MsgModel msg = (MsgModel)message.Body;
            Console.WriteLine(msg.id+msg.Name);
            Console.Read();
        }
    }
}

(二) 本地發/收

//發送
static void Main(string[] args)
{
    MessageQueue MSMQ = CreateMessageQueue(@".\private$\jiyiqin");
    MSMQ.Formatter = new XmlMessageFormatter(new Type[] { typeof(string) });
    Console.WriteLine("是否繼續發送消息:Y/N?");
    string cmd = Console.ReadLine();
    while (cmd.Equals("Y"))
    {
        Sender(MSMQ);
        Console.WriteLine("是否繼續發送消息:Y/N?");
        cmd = Console.ReadLine();
    }
    Console.WriteLine("按任意鍵以停止...");
    Console.ReadKey();
}
private static void Sender(MessageQueue MSMQ)
{
    try
    {
        string random = new Random().Next(0,100).ToString();
        string obj = string.Format("{0} 發送方:{1}",DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), random);
        MSMQ.Send(obj, MessageQueueTransactionType.Single);
        Console.WriteLine(obj);

    }
    catch (Exception ex)
    {
        Console.WriteLine(string.Format("{0} 發送方:{1}",
        DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), ex.Message));
    }
}

public static MessageQueue CreateMessageQueue(string path)
{
    MessageQueue mq = null;              
    if (MessageQueue.Exists(path))
    {
        //存在,創建隊列實例
        mq = new MessageQueue(path);
    }
    else
    {
        //不存在,創建消息隊列
        mq = MessageQueue.Create(path, true);
    }
    return mq;
}

消息隊列即使接收端沒開啓,消息仍會阻塞在隊列中,等接收端開啓,就可以一條條加載消息。

(三) 異地指定隊列增加消息

異地指定隊列增加消息,我們測試同一局域網內兩臺計算機發/收。

///接收端 ip 192.168.2.240
static void Main(string[] args)
{
    MessageQueue MSMQ = CreateMessageQueue(@".\private$\jiyiqin");
    MSMQ.Formatter = new XmlMessageFormatter(new Type[] { typeof(string) });

    Receiver(MSMQ);
}
private static void Receiver(MessageQueue MSMQ)
{
    while (true)
    {
        try
        {
            Message m = MSMQ.Receive(MessageQueueTransactionType.Single);
            Console.WriteLine(string.Format("{0} 接收方:[{1}]",DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), m.Body.ToString()));
        }
        catch (Exception ex)
        {
            Console.WriteLine(string.Format("{0} 接收方:{1}",
            DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), ex.Message));
        }
    }
}

public static MessageQueue CreateMessageQueue(string path)
{
    MessageQueue mq = null;

    if (MessageQueue.Exists(path))
    {
        mq = new MessageQueue(path);
    }
    else
    {
        mq = MessageQueue.Create(path, true);
    }
    return mq;
}

 

遠程隊列的路徑格式:string path = @"Formatname:DIRECT=tcp:192.168.2.240\Private$\jiyiqin";  關鍵字不區分大小寫

MSMQ 判斷隊列是否存在的方法(MessageQueue.Exists(string path))和創建隊列(MessageQueue.Create(string path)),都是不支持遠程隊列的。

1.使用Exists方法會出現錯誤【無法確定具有指定格式名的隊列是否存在】

2.使用Create方法會出現錯誤【無法創建路徑爲 FormatName:DIRECT=tcp:192.168.2.240\Private$\jiyiqin】

3.由於前兩條的限制,如果要訪問遠程專用隊列,則必須保證事先在遠程機器上該隊列是存在的。

static void Main(string[] args)
{
    MessageQueue MSMQ = CreateMessageQueue(@"FormatName:Direct=TCP:192.168.2.240\Private$\jiyiqin");
    MSMQ.Formatter = new XmlMessageFormatter(new Type[] { typeof(string) });

    Console.WriteLine("是否繼續發送消息:Y/N?");
    string cmd = Console.ReadLine();

    while (cmd.Equals("Y"))
    {
        Sender(MSMQ);
        Console.WriteLine("是否繼續發送消息:Y/N?");   
        cmd = Console.ReadLine();
    }

    Console.WriteLine("按任意鍵以停止...");
    Console.ReadKey();
}
private static void Sender(MessageQueue MSMQ)
{
    try
    {
        string random = new Random().Next(0,100).ToString();
        string obj = string.Format("{0} 發送方:{1}",DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), random);
        MSMQ.Send(obj, MessageQueueTransactionType.Single);
        Console.WriteLine(obj);
    }
    catch (Exception ex)
    {
        Console.WriteLine(string.Format("{0} 發送方:{1}",
        DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), ex.Message));
    }
}

public static MessageQueue CreateMessageQueue(string path)
{
    MessageQueue mq = null;  
    // MessageQueue.Exists(path)會報錯
    if (true)
    {
        //存在,創建隊列實例
        mq = new MessageQueue(path);
    }
    else
    {
        //不存在,創建消息隊列
        mq = MessageQueue.Create(path, true);
    }
    return mq;
}

當發送消息到遠程隊列時,系統會在本機的傳出隊列下創建一個臨時隊列,每發送一條消息,該消息都會先存在臨時隊列中,這樣做的目的是防止因遠程隊列無法訪問而丟失消息,

總結

特別注意的是,如果遠程機器不能成功連接,則消息就一直在臨時隊列中存放;如果能成功連接,即使要訪問的隊列並不存在,消息發送程序也不會報錯,並且臨時隊列中的消息會刪除。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章