Tigase插件 – packets是如何被session manager和plugins處理的

本文翻譯自 – http://www.tigase.org/content/how-packets-are-processed-sm-and-plugins
理解插件是如何工做的對開發插件是很是重要的,在不一樣的場景下由不一樣類型的插件來負責處理packet。在開始正式的編碼工做以前,建議你現閱讀一下下面的文檔。 html

什麼是IQ(儲天行注:這一個部分是在翻譯時額外添加的,原文中沒有)

在開始以前,先介紹一下什麼是IQ。這個東西出如今後面的不少地方。Google了一下,IQ的意思是Info/Query:它是一種請求和應答機制,和http有一些相似的地方。 IQ的語意容許一個實體向另外一個實體發送請求,並從另外一個實體獲取應答。請求和應答當中的數據在IQ元素的第一級子節點(命名空間的聲明)當中被定義,請求方實體能夠經過id標籤來跟蹤交互過程。如此一來,IQ交互的數據交換模式就相似於「get/result」 或者 「set/result」(在某些狀況下,也多是get/error和set/error)。若有困惑請參考XMPP官方英文文檔:http://xmpp.org/rfcs/rfc3920.html#stanzas-semantics-iq 算法

Requesting                 Responding
  Entity                     Entity
----------                 ----------
    |                           |
    | <iq type='get' id='1'>    |
    | ------------------------> |
    |                           |
    | <iq type='result' id='1'> |
    | <------------------------ |
    |                           |
    | <iq type='set' id='2'>    |
    | ------------------------> |
    |                           |
    | <iq type='error' id='2'>  |
    | <------------------------ |
    |                           |

爲了可以確保這種方式被執行,有以下規則須要遵照: 數據庫

  1. 每個IQ stanza都必須含有「id」標籤和值
  2. 每個IQ stanza都必須含有「type」標籤和值,且值必須爲以下的幾種:
    • get — 是一個請求信息
    • set — 提供了所須要的數據,設置了新的值或者替換某些已經存在的值
    • result — 一個對應get或set而且執行成功的應答
    • error — 以前發送的一個get或set發生了處理或者傳輸錯誤
  3. 若是一個實體接收到了「set」或「get」 IQ請求,那麼它必須回覆一個「result」或「error」應答,而且應答的id標籤值必須與請求的id標籤值保持一致。
  4. 若是一個實體接收到了「result」或「error」 stanza,那麼它必定不能再返回「result」或「error」應答;可是發出請求的實體能夠能夠繼續發送下一個請求。
  5. 一個「get」 或 「set」類型的 IQ stanza必須包含並只包含一個子元素指明特定請求或應答的語義。
  6. 一個「result」類型的 IQ stanza必須包含零或一個子元素。
  7. 一個「error」類型的IQ stanza應該包含有兩個子元素。第一個子元素包含着與之發生錯誤相對應的「get」或「set」,第二個子元素是<error/>元素。

plugin簡介

插件是一段負責處理特定XMPP stanza的代碼。有專門負責處理消息的插件,有專門負責處理在線狀態的插件,有專門負責處理iq通信錄的插件,也有專門負責處理版本的插件。 服務器

插件經過xmlns和元素名來聲明全部它「感興趣」的那些在特定命名空間下的特定XML元素名,因此你能夠建立一個對那些包含caps元素的packet「感興趣」的插件。 session

對於那些沒有插件「感興趣」的stanza元素,它們會被直接傳遞到消息的目標地址。相反的,也有一些特定的stanza可能會被多個插件「感興趣」,在這種狀況下,多個插件可能會被多個線程同時進行處理,因此沒法確保哪一個插件先進行處理哪一個插件後進行處理。 wordpress

每個stanza都會被session manager一步一步得進行處理,看看下面的圖: 編碼

stanza在SM中的處理 spa

就像圖片裏面展現的那樣,stanza在session manager裏面分四步進行處理: 插件

  1. 預處理 – 全部已加載的預處理器都會接收stanza並進行處理。它們在session manager的內部線程裏被調用,插件本身自己沒有消息隊列。須要注意的是:因爲它們在session manager的內部線程中被調用,算法的執行效率會直接限制SM的執行最小時間(多多少少都會拖慢SM的執行速度)。設置預處理器的目的是爲了阻止packet完成後續處理。若是預處理器返回的結果是true,那麼這個packet就會被阻塞,被阻塞的packet再也不進行後續處理。
  2. 處理 – 若是packet沒有被預處理器阻塞,那麼它會進入這一步進行處理。它會被插入到那些對它的特定元素「感興趣」的處理器隊列中。每個處理器都擁有一個固定長度的處理隊列,並在獨立的線程裏被調用。
  3. 投遞處理 – 若是一個stanza沒有被任何一個處理器處理,那麼它就進入了這一步進行處理。內建的最後一個投遞處理器會對它執行默認處理。一般默認處理是直接把這個packet發送到目的地地址。大多數狀況這個packet是<message/>。
  4. 過濾 – 最後,若是上面的任何一個步驟產生了輸出或result packet,那麼這個輸出或result packet會進入這一步進行處理,每個過濾器均可能產生「阻塞」或「容許經過」的結果。

須要提醒兩點: 線程

  • 有兩個地方或兩種方法可以阻塞/過濾packet。一個地方是在「處理」前被「預處理」過程阻塞;另外一個在「處理」完畢後,處理結果被「過濾」。
  • session manager和處理器的執行方式像是一個packet消費者。packet先被處理,處理一旦結束,它就被銷燬了。因此在把一個packet發送處處理器以前,必須對packet進行復制,設置好全部的屬性而後把它做爲結果輸出。固然處理器也能夠輸出任意多個packet做爲結果,上面四個步驟當中的任何一個步驟均可以產生結果packet。看看下圖:

用戶發送packet

若是packet p1要向服務器外部發送(好比要發送給另一臺服務器的一個用戶,或者另一個組件 – MUC/PubSub/transport之類的),那麼服務器中的第一個處理器必須爲p1建立一個備份p2,而且正確設置好全部的全部的屬性和目的地地址。當p1被SM在處理過程當中銷燬,最終服務器中的插件還可以產生一個新的packet。

若是是組件向用戶發送也是同樣:


組件向用戶發送

在來自組件的packet被銷燬以前,服務器中的一個插件必須作好備份,並最終把備份投遞給用戶。固然了投遞操做在packet沒有被任何插件處理時會做爲默認行爲被執行。

這樣設計的緣由是:輸入packet-p1會在SM中被多個插件在多個線程中同時處理,因此packet的值在處理過程當中必定不能被改變。

最明顯的處理過程是當一個用戶向服務器發送一個指令並但願從服務器得到一個應答:

用戶向服務器發送一個請求並獲取應答

這種設計產生驚人的結果。若是你看完下面兩個用戶之間的交互,你會發現,packet在投遞到目的地以前被拷貝了兩次:



一個用戶向另外一個用戶發送packet

就像圖片所展現的那樣,packet被SM處理了兩次。第一次是做爲用戶A的傳出packet進行處理,第二次是做爲用戶B的傳入packet進行處理。

這樣作的目的是爲了首先肯定用戶A有權限發送packet,而後是肯定用戶B有權限接收數據。若是用戶B不在線,那麼離線消息處理器會把packet保存到數據庫當中。

相關文章
相關標籤/搜索