Message Queue(微軟訊息佇列)是在多個不同的應用之間實現相互連信的一種非同步傳輸模式,相互連信的應用可以分佈於同一台機器上,也可以分佈於相連的網路空間中的任一位置。它的實現原理是:訊息的寄件者把自己想要發送的資訊放入一個容器中(我們稱之為Message),然後把它儲存至一個系統公用空間的訊息佇列(Message Queue)中;本地或者是異地的訊息接收程式再從該隊列中取出發給它的訊息進行處理。
訊息佇列是發送和接收訊息的公用儲存空間,它可以存在於記憶體中或者是物理檔案中。訊息可以以兩種方式發送,即快遞方式(express)和可復原模式(recoverable),它們的區別在於,快遞方式為了訊息的快速傳遞,把訊息放置於記憶體中,而不放於物理磁碟上,以擷取較高的處理能力;可復原模式在傳送過程的每一步驟中,都把訊息寫入物理磁碟中,以得到較好的故障恢複能力。訊息佇列可以放置在發送方、接收方所在的機器上,也可以單獨放置在另外一台機器上。正是由於訊息佇列在放置方式上的靈活性,形成了訊息傳送機制的可靠性。當儲存訊息佇列的機器發生故障而重新啟動以後,以可復原模式發送的訊息可以恢複到故障發生之前的狀態,而以快遞方式發送的訊息則丟失了。另一方面,採用訊息傳遞機制,發送方不必要再擔心接收方是否啟動、是否發生故障等等非必要因素,只要訊息成功發送出去,就可以認為處理完成,而實際上對方可能甚至未曾開機,或者實際完成交易時可能已經是第二天了。
採用MSMQ的好處
採用MSMQ帶來的好處是:由於是非同步通訊,無論是發送方還是接收方都不用等待對方返回成功訊息,就可以執行餘下的代碼,因而大大地提高了事物處理的能力;當資訊傳送過程中,資訊發送機制具有一定功能的故障恢複能力;MSMQ的訊息傳遞機制使得訊息通訊的雙方具有不同的物理平台成為可能。 在微軟的.net平台上利用其提供的MSMQ功能,可以輕鬆建立或者刪除訊息佇列、發送或者接收訊息、甚至於對訊息佇列進行管理。
訊息對列的操作
1. 建立訊息佇列
建立公用訊息佇列——MessageQueue.Create(“MyMachine\MyQueue”)
建立私人訊息佇列——MessageQueue.Create(“MyMachine\Private$\MyPrivateQueue”)
說明:標識Private$表示建立的是私人訊息佇列
2. 隊列引用說明
當你建立了一個MessageQueue組件的一個執行個體以後,就應指明和哪個隊列進行通訊。有3種訪問指定訊息佇列的方法:
1)使用路徑,訊息佇列的路徑被機器名和隊列名唯一確定,因而可以用訊息佇列路徑來指明使用的訊息佇列。
2)使用格式名(format name),它是由MSMQ在訊息佇列建立時或者應用程式在隊列建立以後產生的唯一標識。
3)使用標識名(label),它是訊息佇列建立時由隊列管理者指定的帶由描述意義的名字。
它可能並不唯一。
3、採用路徑(path)方式引用隊列
訊息佇列類型 |
路徑使用格式 |
Public queue |
MachineName\QueueName |
Private queue |
MachineName\Private$\QueueName |
Journal queue |
MachineName\QueueName\Journal$ |
Machine journal queue |
MachineName\Journal$ |
Machine dead letter queue |
MachineName\Deadletter$ |
Machine transactional dead letter queue |
MachineName\XactDeadletter$ |
因為訊息佇列伺服器接收到一個使用路徑方式使用訊息佇列的操作請求時,會去解析出路徑和格式名(format name),因此它的效率上不如格式名方式使用隊列。
訊息佇列未串連時,只能使用格式名方式對它發送訊息。
路徑名的引用除了path屬性以外,還可以由MachineName和QueueName兩個屬性得到。
路徑引用的例子:
MessageQueue1.path=”.\MyQueue”
格式名由不由使用者指定,而是在隊列建立時由隊列管理者自動產生。
。當你的組件作為一個WEB sevice或者是WEB調用的一部分的時候,最好採用格式名方式引用隊列,因為它速度較快。
。當向一個非串連的隊列發送訊息時,應使用格式名方式,因為當隊列不可串連時,路徑解析會導致失敗。
。網路拓撲結構發生變化或者訊息佇列重建以後,格式名會變化。
在delphi中是使用MSMQ
開啟控制台->程式->添加組件,添加訊息佇列
開啟控制台->電腦管理->服務與應用程式->訊息佇列,訊息對列有私人和公有兩種,私人的只有得到對方的認證才可以使用,而公有的不需要。添加私人有訊息Test.
在Delphi中添加MSMQ控制項, TMSMQMessage; TMSMQQueueInfo; TMSMQQueue; TMSMQEvent; 這些控制項在Project->Import type Library裡存在。
unit Unit1;interfaceuses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, MSMQ_TLB, ComObj, StdCtrls, OleServer;type TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure FormCreate(Sender: TObject); private MSMQMessage: TMSMQMessage; MSMQQueueInfo: TMSMQQueueInfo; MSMQQueue: TMSMQQueue; MSMQEvent: TMSMQEvent; //MSMQTransactionAct: MSMQTransaction; MSMQTransactionDispenser: TMSMQTransactionDispenser; { Private declarations } procedure MSMQEventArrived(Sender: TObject; const Queue: IDispatch;Cursor: Integer); public procedure MSMQPostMessage; procedure MSMQReceiveMessage; { Public declarations } end;var Form1: TForm1;implementation{$R *.dfm}procedure TForm1.Button1Click(Sender: TObject);begin MSMQPostMessage;end;procedure TForm1.FormDestroy(Sender: TObject);begin MSMQMessage.Free; MSMQQueueInfo.Free; MSMQQueue.Free; MSMQEvent.Free; MSMQTransactionDispenser.Free;//: TMSMQTransactionDispenser;end;//////////////////////////////////////////////////////////////////////////////////功能:處理接受郵件的非同步方法呼叫//參數:////////////////////////////////////////////////////////////////////////////////procedure TForm1.MSMQEventArrived(Sender: TObject; const Queue: IDispatch; Cursor: Integer);var Msg: Variant;begin Msg := MSMQQueue.Receive_v1();//.Receive;end;//////////////////////////////////////////////////////////////////////////////////功能:將傳入的訊息放入訊息佇列中,首先判斷一下訊息佇列是否存在,若不存在則建立//參數:////////////////////////////////////////////////////////////////////////////////procedure TForm1.MSMQPostMessage;var strBody: string; IsTransactional: OleVariant; MSMQTransactionAct: MSMQTransaction; MSMQTransaction: TMSMQTransaction;begin IsTransactional := True; MSMQTransaction := TMSMQTransaction.Create(nil); MSMQQueueInfo.PathName := '.\private$\test4'; MSMQQueueInfo.RemoteMachineName := 'shangjin'; //或者可以改寫為電腦名稱 MSMQQueueInfo.IsTransactional; try MSMQQueueInfo.Open(MQ_SEND_ACCESS, MQ_DENY_NONE); except on E : EOleException do begin if E.Message = '隊列不存在,或者您沒有足夠的許可權執行該操作。' then begin MSMQQueueInfo.DefaultInterface.Label_ := 'TE'; MSMQQueueInfo.PathName := '.\private$\test7'; MSMQQueueInfo.RemoteMachineName := 'shangjin'; IsTransactional := True; MSMQQueueInfo.DefaultInterface.Create(IsTransactional, EmptyParam); end else raise; end; end; strBody := '123'; (MSMQMessage.DefaultInterface as IMSMQMessage).Body := strBody; MSMQTransactionAct := MSMQTransactionDispenser.BeginTransaction; MSMQQueue.ConnectTo(MSMQQueueInfo.Open(MQ_SEND_ACCESS, MQ_DENY_NONE)); MSMQMessage.Send(MSMQQueueInfo.Open(MQ_SEND_ACCESS, MQ_DENY_NONE));end;//////////////////////////////////////////////////////////////////////////////////功能:從訊息佇列中取訊息,現在還未用到//參數://備忘:僅當訊息佇列應用程式知道隊列的完整路徑名、直接格式名或專用格式名時才能訪// 問專用隊列.// 路徑名:ComputerName\private$\QueueName。// 本機電腦上的路徑名: \private$\QueueName。// 直接格式名:DIRECT=ComputerAddress\PRIVATE$\PrivateQueueName。// Private format name: PRIVATE=ComputerGUID\QueueNumber。// 使用前要先設定許可權,才可訪問。// 對於要訪問專用隊列的本機電腦上的訊息佇列應用程式,該應用程式僅需要知道// 隊列的路徑名。對於遠端電腦上的訊息佇列應用程式,應用程式需要知道隊列的// 直接或專用格式名才能訪問此類隊列// 專用格式名可用MSMQQueue.QueueInfo.FormatName獲得////////////////////////////////////////////////////////////////////////////////procedure TForm1.MSMQReceiveMessage;begin MSMQQueueInfo.PathName := 'shangjin\Private$\Test'; MSMQQueue.Disconnect; MSMQQueue.ConnectTo(MSMQQueueInfo.Open(MQ_RECEIVE_ACCESS, MQ_DENY_NONE)); MSMQEvent.OnArrived := MSMQEventArrived; MSMQQueue.EnableNotification(MSMQEvent.DefaultInterface);end;procedure TForm1.FormCreate(Sender: TObject);begin MSMQMessage := TMSMQMessage.Create(nil); MSMQQueueInfo := TMSMQQueueInfo.Create(nil); MSMQQueue := TMSMQQueue.Create(nil); MSMQEvent := TMSMQEvent.Create(nil); MSMQTransactionDispenser := TMSMQTransactionDispenser.Create(nil);end;end.