Tigase--packet流轉機制

初看Tigase的packet內部流轉機制。Tigase通過tigase.io包當中的代碼讀取網絡中的字節數組,然后通過tigase.net包當中的類把字節數組轉換為字符,最后通過tigase.xml包當中的XML解析器把這些字符轉換成XML DOM對象。

圖片流程說明

看tigase源碼你會發現所有的tigase處理都是基于多線程,每個component都有自己的in和out處理線程,線程間的數據傳輸通過queue
總的流程大致就是:


Tigase的packet內部流轉機制

文字流程說明

下面是請求和響應的步驟說明(只列出了關鍵的步驟)。

A. 從client到server的過程(請求-Request)

ClientConnectionManager和MessageRouter都間接或直接繼承了AbstractMessageReceiver。

tigase.server.AbstractMessageReceiver

– 它已經實現了四個接口:ServerComponent,MessageReceiver,Configurable和StatisticsContainer。

它通過自己的多個線程來管理內部數據隊列,且能避免死鎖。

它使用事件驅動的方式來處理數據,當packet被發送到AbstractMessageReceiver實例的abstract void processPacket(Packet packet)方法時,就立即啟動了packet的處理工作。當然你還是需要實現抽象類當中的抽象方法,如果你還希望輸出packet數據(例如當它收到請求時還需要發送響應),可以調用boolean addOutPacket(Packet packet)方法。

a. XMPPIOService負責接收客戶端報文并轉換為對應的packet放入隊列receivedPackets(相當于in_queues)中,而SocketThread負責創建ReadThread和WriteThread線程,

ResultsListener則是SocketThread的一個內部類。ResultsListener負責調度socketReadThread()和
socketWriteThread(), Client2Server讀取和寫入數據包的IO操作主要由XMPPIOService來完XMPPIOService實例則在read和write線程中被使用。

b. ClientConnectionManager則負責從XMPPIOService獲取receivedPackets,并對收到的報文進行處理,并將處理后的報文放入MessageRouter的out_queues隊列中。

c.MessageRouter重寫了AbstractMessageReceiver的processPacket方法,在該方法中MessageRouter通過packet.getTo()得到組件的名稱并轉發packet到該組件的in_queues隊列中,該目標服務組件(如ses-man,即SessionManager)可能在本機服務器上,也可能在該域(domain)集群的其他服務器上運行MessageRouter的查找順序是先查本機服務器,找不到的話再去集群中查找;如果找到則將packet轉發給目標組件處理,如果沒找到則返回沒有找到目標組件的錯誤消息。

d. 我們的組件一般都有自己的in_queues和out_queues. 當前組件的in_queues的數據來自于上一組件的out_queues。

int  queueIdx = Math.abs(hashCodeForPacket(packet) % in_queues_size*);
boolean  result = in_queues.get(queueIdx).offer(packet, packet.getPriority().ordinal());

//這里的packet數據來自于packetFrom="xxx",即傳給當前組件的上一組件。

B.從Service到Client的過程(響應-Response)

服務端響應的數據也是放到out_queues中的,各組件的對應的線程會對out_queues中的packet的to屬性做解析,并將消息轉發到指定目標。其實消息的流轉傳遞機制實現的核心就是packet的 from包含packetFrom和stanzaFrom) 和 to(packetTo和stanzaTo)屬性,路由的路徑會默認先取packetFrom或packetTo,其次再去取stanzaFrom和stanzaTo。

客戶端發送一條ping命令

<iq type='get' id='purplee4ad721'>
<ping xmlns='urn:xmpp:ping'/>
</iq>

IOService.java

public abstract class IOService<RefObject>
            implements Callable<IOService<?>>, TLSEventHandler,
            IOListener {

/**接收報文后call->處理客戶端報文數據信息*/
@Override
public IOService<?> call() throws IOException {
   writeData(null);

   boolean readLock = true;

   if (stopping) {
      stop();
   } else {
      readLock = readInProgress.tryLock();
      if (readLock) {
         try {
            processSocketData();
            if ((receivedPackets() > 0) && (serviceListener != null)) {
               serviceListener.packetsReady(this);
            }    // end of if (receivedPackets.size() > 0)
         } finally {
            readInProgress.unlock();
            if (!isConnected()) {
               // added to sooner detect disconnection of peer - ie. client
               if (log.isLoggable(Level.FINEST)) {
                  log.log(Level.FINEST, "{0}, stopping connection due to the fact that it was disconnected, forceStop()", toString());
               }
               forceStop();
            }
         }
      }
   }

   return readLock
         ? this
         : null;
}

/**
 * Describe
 * <code>writeData</code> method here.
 * 這里是最后響應消息給客戶端的方法,寫入TCP連接中的Socket
 * @param data a
 * <code>String</code> value
 */
protected void writeData(final String data) {

返回消息前還調用了下面兩個類的對應write方法

SocketIO.java
@Override
public int write(final ByteBuffer buff) throws IOException {
}


TLSIO.java
public class TLSIO implements IOInterface {
         private int writeBuff(ByteBuffer buff) throws IOException {
          }
}

IOService打包好了消息之后形成響應的packet包,->然后再執行到ConnectionManager的writePacketToSocket()方法->再執行到ClientConnectionManager的processPacket方法。

至此本次消息的請求和響應結束!server會繼續通過AbstractMessageReceiver獲取下一條消息進行處理,如此循環。。。


  1. tigase.server.ServerComponent – 這是一個非常基本的component接口。所有的component都必須實現接口中定義的方法。

  2. tigase.server.MessageReceiver – 這個接口extends ServerComponent,所有希望接收數據packets的Component都需要實現接口中定義的方法,比如session manager和c2s connection manager。
    tigase.conf.Configurable – 如果希望components可以被配置,則需要實現這個接口,所有默認定義基本都在這。在運行時,配置信息會被推送到這種類型的對象。components必須能夠在運行時對變更的配置項進行處理,這一點在實現時要留神。

  3. tigase.disco.XMPPService – 實現了這個對象的類可以對“ServiceDiscovery”請求做出響應。

  4. tigase.stats.StatisticsContainer – 實現了這個對象的類可以返回運行時的統計信息。任何一個對象都可以實現這個接口用來收集統計信息

  5. tigase.server.AbstractMessageReceiver – 它已經實現了四個接口:ServerComponent,MessageReceiver,Configurable和StatisticsContainer。它通過自己的多個線程來管理內部數據隊列,且能避免死鎖。
    它使用事件驅動的方式來處理數據,當packet被發送到AbstractMessageReceiver實例的abstract void processPacket(Packet packet)方法時,就立即啟動了packet的處理工作。當然你還是需要實現抽象類當中的抽象方法,如果你還希望輸出packet數據(例如當它收到請求時還需要發送響應),可以調用boolean addOutPacket(Packet packet)方法。

  6. tigase.server.ConnectionManager – 這是一個extend AbstractMessageReceiver的抽象類。正如其名,這個類專注于對連接進行管理工作。如果你的組件需要通過網絡直接發送或接受數據(比如c2s connection,s2s connection 或者 連接到外部第三方jabber服務),你可以把它作為基類進行擴展。它會幫你把所有和網絡有關的工作都打理好(例如io,重連,socket監聽和連接握手等工作)。
    如果你extend這個類,你需要知道數據來源于哪里:如果來源于MessageRouter,那么abstract void processPacket(Packet packet)方法會被調用; 如果來源于網絡連接,那么abstract Queue processSocketData(XMPPIOService serv)方法會被調用。

網絡

connectionManager同時協調ConnectionOpenThread與SocketThread。
ConnectionOpenThread脫離上述組件,屬于網絡層實現,操作selector。它負責Selector.open。
IOService提供線程安全的call方法,XMPPIOService繼承它,保存了連接信息,每個連接一個IOService。
SocketThread在實例化時,會啟動多個線程,同時盯住selector。負責將每個確定的IOService進行數據處理。
實現ConnectionOpenListener接口accept方法接收SocketChannel,組裝IOService,交由SocketThread處理。
ConnectionManager用ConcurrentHashMap記錄了所有的連接。
零碎

AbstractMessageReceiver.addPacket 往自己的in_queue里加數據,是阻塞的,如果滿了會出事。
AbstractMessageReceiver.addPacketNB 往自己的in_queue里加數據,非阻塞的,和上一個的區別在于,一個是put一個是offer到queue。
AbstractMessageReceiver.addPackets 來一堆數據。
所有in_queue里的數據,會被processPacket方法所處理。
對應有addOutPacket。
所有out_queue里的數據,都默認扔給parent的in_queue,沒有parent就扔到自己的in_queue。
所有in_queue的數據,都由processPacket具體的實現來處理。

企業級獨立部署應用:知行辦公http://zx.naton.cn
【總監】十二春秋之,3483099@qq.com
【Master】zelo,616701261@qq.com
【運營】運維艄公,897221533@qq.com
【產品設計】流浪貓,364994559@qq.com
【體驗設計】兜兜,2435632247@qq.com
【iOS】淘碼小工,492395860@qq.com;iMcG33K,imcg33k@gmail.com
【Android】人猿居士,1059604515@qq.com;思路的頓悟,1217022114@qq.com
【java】首席工程師MR_W,feixue300@qq.com
【測試】土鏡問道,847071279@qq.com
【數據】fox009521,42151960@qq.com
【安全】保密,你懂的。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,915評論 18 139
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 173,242評論 25 708
  • 從三月份找實習到現在,面了一些公司,掛了不少,但最終還是拿到小米、百度、阿里、京東、新浪、CVTE、樂視家的研發崗...
    時芥藍閱讀 42,366評論 11 349
  • 今日看到《失控的“中杯”,星巴克們到底錯在哪?》一文,想起幾年前曾看過的一本書——《在星巴克要點大杯咖啡》(書中以...
    風起云卷縱四海閱讀 2,268評論 0 0