我們在使用 ASP 程式時常常會遇到這些情況:某個進程花費了過長的時間而導致在用戶端到期、訪問者已經放棄了對你的網站的訪問而離開去了別的網站、或你的伺服器上阻塞了大量的死隊列時,系統出現 "Server is too busy" 錯誤資訊。 當你在設計網站的過程中碰到這些問題時,一個有效解決辦法就是使用 Microsoft Message Queue (MSMQ) 來結束這些進程,讓網站恢複正常! 到底 MSMQ 是個什麼樣的東西呢?我們下面作一下瞭解: 一、 Microsoft Message Queue 的基本介紹: MSMQ ( 代號又叫 "Falcon") 是運行在 Windows NT 的服務 , 它提供運用程式之間的非同步通訊。你可以在 NT4 Option Pack 中找到它。 MSMQ 的基本概念非常的簡單:它可以被看成是運用程式之間的 email :一個訊息被打包到一個特定類型的容器中,並把這個訊息儲存到一個用與特別作用的隊列中直到收信者接受該訊息為止。這些隊列能夠確保 MSMQ 的傳送,而不管當前網路連接的狀況如何。 象所有的電子郵件一樣, MSMQ 訊息有一個寄件者和一個接收者 , 其中的接收者應該能夠訪問隊列。一個單一隊列中的一個單獨訊息,它擁有多個接受者例如 respinder 。而訊息的寄件者通常是 Web Server(IIS) 。 MSMQ 也能夠和其他訊息系統進行通訊。例如: Sun Solaris, HP-UNIX,OS/2, VMS, AS/400 平台。像其他的 BackOffice 服務一樣, MSMQ 有一個 COM API ( mqoa.dll ) 提供給開發人員開發程式。其中最常用的三個類為: MSMQQueueInfo, MSMQQueue, MSMQMessage 。 ( 1 )、 MSQMQueueInfo MSMQQueueInfo 允許你建立,開啟,刪除隊列中的訊息 . 要和隊列建立聯絡首先需要設定 PathName ,這是一個命名隊列的屬性,它告訴 MSQM 是哪台機器上的隊列。 < % Dim objQueueInfo Dim objQueue Set objQueueInfo=Server.CreateObject("MSMQ.MSMQQueueInfo") objQueue.PathName = ".\MyQu" Set objQueue = objQueueInfo.Open(MQ_SEND_ACCESS, MQ_DENY_NONE) %>
上面的代碼開啟一個叫 MyQueue 的本地隊列。如果隊列在另外一台伺服器上,代碼應該是這樣的: objQueue.PathName = "SomeOtherComputer\MyQu" 開啟隊列中有兩個參數: Access 和 ShareMode 。 Access 表示將要對隊列執行什麼操作。一般有三個操作: MQ_PEEK_ACCESS (32), MQ_RECEIVE_ACCESS (1), MQ_SEND_ACCESS (2) 。 MQ_PEEK_ACCESS 用來在特定的隊列中尋找訊息。但對該訊息不進行操作。 MQ_RECEIVE_ACCESS 用來在讀取隊列中的訊息後刪除它。 MQ_SEND_ACCESS 用來在隊列中發送訊息 , 但不接收訊息。 需要注意的是在使用開啟操作後返回了一個 MSMQQueue 對象。下面是一個典型的建立和刪除操作例子: < % Dim objQueue Set objQueue = Server.CreateObject("MSMQ.MSMQQueueInfo") objQueue.PathName = ".\MyQu" objQueue.Create %> < % Dim objQueue Set objQueue = Server.CreateObject("MSMQ.MSMQQueueInfo") objQueue.PathName = ".\MyQu" objQueue.Delete %>
( 2 )、 MSMQQueue MSMQQueue 類用來描述一個在 MSMQ 服務中開啟的隊列。該類提供了一個用來在指標隊列中的訊息進行迴圈的功能。你不能夠開啟一個使用了 MSMQQueue 類的隊列要這麼幹只能夠使用 MSQMQueueInfo (見上例),雖然許多 ASP 運用程式通常使用 MSMQ 來發訊息,但是很多時候也需要 ASP 來顯示這個訊息的具體內容。 擷取訊息的方式有兩種:同步方式,非同步方式,但是 ASP 只能夠使用同步方式。這是因為 ASP 不能夠在服務端申明一個 WithEvents 變數。 下面先舉一個非同步方式使用 MSMQ 的例子(僅 VB 中) Option Explicit Dim m_objQueueInfo As New MSMQQueueInfo Dim m_objQueue As MSMQQueue Dim WithEvents m_objMSMQEvent As MSMQEvent Private Sub Form_Load() m_objQueueInfo.PathName = ".\MyQu" m_objQueueInfo.Label = "My Sample Queue" On Error Resume Next m_objQueueInfo.Create On Error GoTo 0 Set m_objQueue = m_objQueueInfo.Open(MQ_RECEIVE_ACCESS, MQ_DENY_NONE) Set m_objMSMQEvent = New MSMQEvent m_objQueue.EnableNotification m_objMSMQEvent, MQMSG_CURRENT, 1000 End Sub Private Sub m_objMSMQEvent_Arrived(ByVal Queue As Object, ByVal Cursor As Long) Dim m_objMessage As MSMQMessage Set m_objMessage = Queue.PeekCurrent MsgBox "Message Received: " & m_objMessage.Label m_objQueue.EnableNotification m_objMSMQEvent, MQMSG_NEXT, 10000 End Sub Private Sub m_objMSMQEvent_ArrivedError(ByVal Queue As Object, ByVal ErrorCode As Long, ByVal Cursor As Long) MsgBox "Error accorded: " & ErrorCode End Sub
這段代碼首先建立一個隊列(如果它還不存在的話)。然後 m_objMSMQEvent 對象通過調用 EnableNotification 串連到 MSMQQueue 對象。一旦串連到 MSMQEvent 對象 , 接下來需做的僅僅是完成 Arrived 和 Arrived_Error ( 可選的 ) 事件。 Arrived 事件當一個新的訊息到達隊列時將被觸發該事件返回兩個指標 , 一個是指向隊列中應該從來開始讀訊息的位置,另外一個是當前的位置。如果發生錯誤,將觸發 ArrivedError 事件當同步擷取訊息時,會一直等到訊息可擷取或則逾時時程式才會不被掛起。代碼如下: Public Sub DisplayMessages() Dim objQueueInfo As New MSMQQueueInfo Dim objQueue As MSMQQueue Dim objMessage As MSMQMessage objQueueInfo.PathName = ".\MyQu" objQueueInfo.Label = "My Sample Queue" On Error Resume Next objQueueInfo.Create On Error GoTo 0 Set objQueue = objQueueInfo.Open(MQ_RECEIVE_ACCESS, MQ_DENY_NONE) Do While True Set objMessage = objQueue.Peek(, , 1000) If objMessage Is Nothing Then Exit Do MsgBox "Message: " & objMessage.Label Loop MsgBox "No more new messages." objQueue.Close Set objMessage = Nothing Set objQueue = Nothing Set objQueueInfo = Nothing End Sub ( 3 )、 MSMQMessage MSMQMessage 類支援隊列中訊息的所有屬性。 MSMQ 訊息有兩個方法和繁多的屬性。其中兩個最主要的屬性是: Body 和 LabeL 。最主要的方法有 Send 。有兩種方法來擷取訊息: opening , peeking 。當使用 opening 方式後,該訊息將會被刪除掉;當使用 peeking 方式後,該訊息仍然儲存在隊列中直到它到期。它們的傳回值都是指向該訊息的指標。下例的代碼將開啟一個訊息,並顯示其 Body 和 Label Private Sub LookForMessage() Dim objQInfo As New MSMQQueueInfo Dim objQReceive As MSMQQueue Dim objMessage As MSMQMessage objQInfo.PathName = ".\test" Set objQReceive = objQInfo.Open(MQ_RECEIVE_ACCESS, MQ_DENY_NONE) Set objMessage = objQReceive.Receive(, , , 1000) If Not objMessage Is Nothing Then MsgBox objMessage.Label & " - " & objMessage.Body Else Msgbox "Nothing in the queue" End If objQReceive.Close Set objQInfo = Nothing Set objQReceive = Nothing Set objMessage = Nothing End Sub
這段代碼開啟一個隊列並在該隊列中尋找訊息,使用 Receive 方法,主要是設定一個 1000 微秒的逾時 , 它告訴 MSMQ1000 微秒後停止尋找設定一個非常段的逾時的功能主要是用來檢查是否存在訊息而不是等候一個訊息。也就是說如果你知識想看看是否有訊息可以使用該方法。如果無訊息,返回的指標為空白 (If Not objMessage Is Nothing) 。下面是發送一個訊息的代碼: < % Dim objQInfo Dim objQSend Dim objMessage Set objQInfo = Server.CreateObject("MSMQ.MSMQQueueInfo") objQInfo.PathName = ".\test" Set objQSend = objQInfo.Open(MQ_SEND_ACCESS, MQ_DENY_NONE) Set objMessage = Server.CreateObject("MSMQ.MSMQMessage") objMessage.Label = "This is the label." objMessage.Body = "This is the body." objMessage.Send objQSend objQSend.Close Set objQInfo = Nothing Set objQSend = Nothing Set objMessage = Nothing %>
對於 MSMQ 的有關基本知識我們已做了舉例介紹,下面將就它的具體運用進行的瞭解及探討! 在運用程式中 MSMQ 可以有很多的運用,但是最普遍的運用是卸載另一個線程中的進程。 ( 例如和 MSMQ 在同一台機器上的 IIS) 或則是另外一台機器上的 IIS. 通過卸載這些阻塞的進程,就能夠使得 ASP 程式能夠繼續運行下去了。 一般來說,判斷是否需要卸載任務進程要做兩件事: 一是根據該進程啟動並執行時間。 二是根據使用者是否有回應(例如聊天室裡面某個使用者幾個小時都沒說話了)。 例如:如果服務端的一個 Web 網頁的任務花費了太長的時間 , 使用者會得到一個網頁逾時的錯誤資訊,我們一般可以通過重新單擊重新整理或者簡單的放棄這個網頁。但現在可以改變一下處理方式,例如進行幕後處理,而不是簡單的靠增加處理網頁的時間方式。要知道,幕後處理方式也能夠提高網站效能的。 MSMQ 還有一個功能,就是能夠控制訊息的 body 中特定的一個 COM 物件。只要該對象支援 Idispatch 和 Ipersist (IPersistStream or IPersistStorage ) 介面就行。 其中最常用的,能支援的兩個就是 ADODB.Recordset ( 或 ADOR.Recordset ) 和 Word.Document 。在下面我們舉一個處理 ADODB.Recordset 例子。 例:如何處理 ADODB.Recordset : Public Sub SendRecordsetInMessage() Dim objQInfo As New MSMQ.MSMQQueueInfo Dim objQSend As MSMQ.MSMQQueue Dim objMessage As New MSMQ.MSMQMessage Dim objRS As New ADOR.Recordset Dim a As New MSMQQueue With objRS .CursorLocation = adUseClient .Fields.Append "FN", adVarChar, 25 .Fields.Append "LN", adVarChar, 25 .Open .AddNew .Fields("FN") = "Chris" .Fields("LN") = "Blexrud" .Update .AddNew .Fields("FN") = "Shayna" .Fields("LN") = "Blexrud" .Update End With objQInfo.PathName = ".\test" Set objQSend = objQInfo.Open(MQ_SEND_ACCESS, MQ_DENY_NONE) objMessage.Label = "Recordset State!!!!" objMessage.Body = objRS objMessage.Send objQSend objQSend.Close Set objQInfo = Nothing Set objQSend = Nothing Set objMessage = Nothing Set objRS = Nothing End Sub
瞭解了 MSMQ 嗎?我想現在對於 ASP 的進程死結,你已經有了很好的解決方案了吧!希望大家能通過以上文字,真正瞭解 MSMQ ,及通過 MSMQ 控制 ASP 進程的方法! |