多線程操作消息隊列

http://blog.csdn.net/nyzfl/article/details/1537136

 1.       消息隊列(Message Queue):

a.       添加System.Messaging.dll.
b.       簡介
利用 MSMQMicrosoft 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]屬性不用於專門的消息服務中。
c.        .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 方法允許主應用程序任務在消息到達隊列之前,在單獨的線程中繼續執行。這些方法通過使用回調對象和狀態對象進行工作,以便在線程之間進行信息通訊。
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);
        }
        
//同步接收
        private void btnReceiveMessage_Click(object sender, System.EventArgs e)
        {
            
try
            {
                
//Open Queue
                System.Messaging.MessageQueue queue=new System.Messaging.MessageQueue("./Private$/MSMQDemo");
                
//Receive message,同步的Receive方法阻塞當前執行線程,直到一個message可以得到
                lock(queue)
                {
                    System.Messaging.Message message
=queue.Receive(new TimeSpan(0,0,0,1),System.Messaging.MessageQueueTransactionType.Single);
                    message.Formatter
=new System.Messaging.XmlMessageFormatter(new Type[]{typeof(string)});
                    txtReceiveMessage.Text
=message.Body.ToString();
                }
            }
            
catch(System.Messaging.MessageQueueException ex)
            {
                
//超時
                MessageBox.Show(ex.MessageQueueErrorCode.ToString());
            }
    }
結束.

        
//異步接收
        private void Receive1_Click(object sender, System.EventArgs e)
        {
            System.Messaging.MessageQueue mq1
=new System.Messaging.MessageQueue("./Private$/MSMQDemo");
            mq1.ReceiveCompleted
+=new System.Messaging.ReceiveCompletedEventHandler(ReceiveEvt);
            mq1.BeginReceive();
        }

        
private void ReceiveEvt(object source,System.Messaging.ReceiveCompletedEventArgs asyncResult)
        {
            
try
            {
                System.Messaging.MessageQueue mqReceive
=(System.Messaging.MessageQueue)source;
                System.Messaging.Message m
=mqReceive.EndReceive(asyncResult.AsyncResult);
                
//此事m爲異步接收到的消息
                
//在此插入處理消息的代碼
                m.Formatter=new System.Messaging.XmlMessageFormatter(new Type[]{typeof(string)});
                txtReceiveMessage.Text
=m.Body.ToString();
                mqReceive.BeginReceive();
//接收下一次事件
            }
            
catch(System.Messaging.MessageQueueException e)
            {
                System.Windows.Forms.MessageBox.Show(e.MessageQueueErrorCode.ToString());
                System.Windows.Forms.MessageBox.Show(e.Message);
            }
    }

好處:當第二次點發送消息的時候,自動接收。

D.在後臺寫的操作類。

        /// <summary>
        
/// 檢查隊列,如果隊列不存在,則建立 
        
/// 隊列名稱
        
/// </summary>

        
/// <param name="path">路徑</param>
        private static void EnsureQueueExists(string path)
        {
            
if(!System.Messaging.MessageQueue.Exists(path))
            {
                System.Messaging.MessageQueue.Create(path);
                System.Messaging.MessageQueue mqTemp
=new System.Messaging.MessageQueue(path);
                mqTemp.SetPermissions(
"Everyone",System.Messaging.MessageQueueAccessRights.FullControl);
                
///不知道該給什麼樣的權限好,所以就給了Everone全部權限了,當然大家最好自己控制一下

            }
        }

        
/// <summary>

        
/// 發送對象到隊列中
        
/// 隊列名稱,因爲隊列名稱在一個應用中應該不改變的,所以大家最好寫在配置文件中
        
/// 要發出去的對象
        
/// </summary>

        
/// <param name="QueuePath"></param>
        
/// <param name="MessageText"></param>
        public static void SendQueue(string QueuePath,string MessageText)
        {
            System.Messaging.MessageQueue mqSend
=new System.Messaging.MessageQueue(QueuePath,false);
            EnsureQueueExists(QueuePath);
            System.Messaging.Message sq
=new System.Messaging.Message();
            sq.Body
=MessageText.Trim();
            sq.Formatter
=new System.Messaging.XmlMessageFormatter(new Type[]{typeof(string)});
            mqSend.Send(sq);
        }

        
/// <summary>

        
/// 從隊列中取出對象列表
        
/// 隊列名稱
        
/// 不知道怎麼用
        
/// </summary>

        
/// <param name="QueuePath"></param>
        
/// <returns></returns>
        public static System.Collections.ArrayList GetMessage(string QueuePath)
        {
            System.Messaging.Message sq
=new System.Messaging.Message();
            System.Messaging.MessageQueue mq
=new System.Messaging.MessageQueue(QueuePath,false);
            mq.Formatter
=new System.Messaging.XmlMessageFormatter(new Type[]{typeof(string)});
            System.Messaging.Message[] arrM
=mq.GetAllMessages();
            mq.Close();
            System.Collections.ArrayList al
=new System.Collections.ArrayList();
            
foreach(System.Messaging.Message m in arrM)
            {
                sq
=m.Body as System.Messaging.Message;
                al.Add(sq);
            }
            
return al;
        }

        
/// <summary>

        
/// 得到計算機消息隊列中的數量,做循環進行計數
        
/// </summary>

        
/// <param name="QueuePath"></param>
        
/// <returns></returns>
        public static uint Count(string QueuePath)
        {
            
//變量,存放數量

            uint numberItems=0;
            
//連接到隊列

            System.Messaging.MessageQueue mq=new System.Messaging.MessageQueue(QueuePath);
            System.Messaging.MessageEnumerator myEnumerator
=mq.GetMessageEnumerator();
            
while(myEnumerator.MoveNext())
            {
                numberItems
++;
            }
            
return
 numberItems;
        }

E.後臺寫的利用多線程監聽的操作類。

private string m_MachineName;
        
private string m_QueueName;
        
public bool flag=true;

        
/// <summary>

        
/// 重載構造函數,接收必要的隊列信息
        
/// </summary>

        
/// <param name="MachineName"></param>
        
/// <param name="QueueName"></param>
        public MQListen(string MachineName,string QueueName)
        {
            m_MachineName
=MachineName;
            m_QueueName
=QueueName;
        }

        
public void Listen()
        {
            
//創建一個MessageQueue對象

            System.Messaging.MessageQueue MQ=new System.Messaging.MessageQueue();
            
//設置MessageQueue對象的路徑屬性

            MQ.Path=m_MachineName+"/private$/"+m_QueueName;
            
//創建一個Message對象

            System.Messaging.Message message=new System.Messaging.Message();
            
//重複上述步驟,直到收到中止

            while(flag)
            {
                
try

                {
                    
//休眠以在中斷髮出時捕捉中斷
                    System.Threading.Thread.Sleep(100);
                    
//將Message對象設置爲與接收函數的結果相等
                    
//持續時間(天,時,分鐘,秒)

                    message=MQ.Receive(new TimeSpan(0,0,10,10));
                    
//顯示已接受消息的標籤

                    System.Windows.Forms.MessageBox.Show("Label:"+message.Label);
                }
                
catch(System.Threading.ThreadInterruptedException e)
                {
                    
//從主線程捕捉ThreadInterrupt並退出

                    Console.WriteLine("Exiting Thread");
                    message.Dispose();
                    MQ.Dispose();
                    
break;
                }
                
catch(Exception GenericException)
                {
                    
// 捕捉接收過程中拋出的所有異常。

                    Console.WriteLine(GenericException.Message);
                }
            }
        }

啓動和終止線程操作同步消息隊列:
    簡單:
            啓動:        MultiThreadedMQListener.MQListen objMQListen
=new WinFormExample1._0320.MultiThreadedMQListener.MQListen(".","MSMQDemo");
            System.Threading.Thread thread
=new System.Threading.Thread(new System.Threading.ThreadStart (objMQListen.Listen));
            t.Start();
            終止:            MultiThreadedMQListener.MQListen objMQListen
=new WinFormExample1._0320.MultiThreadedMQListener.MQListen(".","MSMQDemo");
            objMQListen.flag
=false;
    複雜(線程池):
        
private void StartThreads()
        {
            
int LoopCounter;//線程計數

            StopListeningFlag=false;// 跟蹤輔助線程是否應當終止的標誌。
            
//將一個包含 5 個線程的數組聲明爲輔助線程。

            Thread[] ThreadArray=new Thread[5];
            
//聲明包含輔助線程的所有代碼的類。

            MQListen objMQListen=new MQListen(server.Text,Queue.Text);
            
for(LoopCounter=0;LoopCounter<ThreadArray.Length;LoopCounter++)
            {
                
//創建一個 Thread 對象。

                ThreadArray[LoopCounter]=new Thread(new ThreadStart(objMQListen.Listen));
                
//啓動線程將調用 ThreadStart 委託。

                ThreadArray[LoopCounter].Start();
            }
            statusBar1.Text
=LoopCounter.ToString()+" listener threads started";
            
while(!StopListeningFlag)
            {
                
//等待用戶按下停止按鈕。
                
//在等待過程中,讓系統處理其他事件。

                System.Windows.Forms.Application.DoEvents();
            }
            statusBar1.Text
="Stop request received,stopping threads";
            
//向每個線程發送一箇中斷請求。

            for(LoopCounter=0;LoopCounter<ThreadArray.Length;LoopCounter++)
            {
                ThreadArray[LoopCounter].Interrupt();
            }
            statusBar1.Text
="All Threads have been Stopped";
        }

        
private bool StopListeningFlag=false;

        
private void start_Click(object sender, System.EventArgs e)
        {
            statusBar1.Text
="Starting Threads";
            StartThreads();
        }

        
private void stop_Click(object sender, System.EventArgs e)
        {
            StopListeningFlag
=true
;
        }

異步操作消息隊列:

先聲明一個   
 
System.Threading.ManualResetEvent socketEvent=new System.Threading.ManualResetEvent(false);    
  
先socketEvent.Reset();

BeginReceive();監聽;   
  
然後socketEvent.WaitOne();

回調函數中   
  先socketEvent.Set();  然後使用EndReceive ()來完成數據報的接收  


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