1. 程式人生 > >To Be the OnE

To Be the OnE

Apache mina基本上可以看成是一個基於java nio的web通訊框架,特點是程式設計介面簡單,但是功能完善,效能也不錯。
mina可以提供基於TCP、UDP、符合RS232的順序通訊以及vm內部的基於管道的通訊,這些通訊方式都以一致的介面暴露,通過介面的不同實現完成。首先來看一下這些介面已經他們之間的互動關係。
主要的介面包括以下幾個:
IOService:IOAcceptor和IOConnector的父介面,定義了兩者都會用到的一些方法;
IOAcceptor:伺服器端需要實現的介面;
IOConnector:客戶端需要實現的介面;
IOProcessor:mina內部使用的一個介面,用來管理session,並且利用session來完成具體的io操作
IOSession:每個IOSession都表示一種型別的連線,並且維護與這個連結有關的所有資訊。
IOFilter:mina中,傳送和接收訊息時都需要經過一個過濾器鏈,這個鏈用來進行日誌記錄、編碼轉換等工作。

這幾個介面之間的協作關係如下:
[img]http://dl.iteye.com/upload/attachment/367531/7f38019e-e5ed-3dc8-b6ee-b93cb28bed8c.png[/img]
另外還有一個介面,叫做IOHandler,這個介面被註冊到IOAcceptor或者IOConnector中,是客戶端必須要實現的一個介面,通過這接口裡面的方法客戶端可以通過mina提供的通訊框架傳送或者接收網路訊息,以及其他的一些事件,比如Session建立等。這個介面接收到的訊息是經過IOFilter鏈過濾過的,通過這個介面傳送的訊息也需要經過IOFilter鏈的過濾。讀網路上的資料的時候過濾發生在IOProcessor中,而由於寫是在IOHandler中直接觸發的,所以寫的過濾是在IOSession中發生的。

下面簡要介紹一下TCP通訊方式下,伺服器端的啟動、繫結和channel建立過程,客戶端的連線和channel簡歷過程大致類似。

TCP的通訊涉及到伺服器端和客戶端,在mina中伺服器端使用一個叫做NioSocketAcceptor的類來表示,它繼承自AbstractPollingIoAcceptor,從名字可以看出,mina的TCP伺服器端實現的基本原理是輪詢,在老版本的mina中(也就是netty)中就是這麼實現的,只不過由於Java後來有了nio,也就把實現遷移到nio上了。
建立NioSocketAcceptor的時候會建立一個NIOProcessor,這是IOProcessor的一個實現類,這個Processor會被用來管理後續建立的NIOSession。在預設情況下,如果不指定IOProcessor,mina會把這個NIOProcessor在封裝一下,變成一個SimpleIoProcessorPool,這個IOProcessor池同時也實現了IOProcessor介面,所以可以被當成IOProcessor來使用,這個是一個Wrapper模式的應用。在SimpleIoProcessorPool內部,會根據IOProcessor的具體型別建立一個或者多個IOProcessor例項,在使用NioSocketAcceptor的時候,就會建立一個或者多個NIOProcessor的例項。這個不是真正意義上的池,因為內部實現是把所有的NIOProcessor放到一個數組中,在有新的NIOSession被建立的時候會從陣列中根據NIOSession的id對陣列的長度取模,然後拿到一個IOProcessor來處理NIOSession。這些初始化工作完成之後,NioSocketAcceptor就會開啟java nio裡面的Selector,但是這個時候還沒有真正開始接受連線請求,我們需要把這個NioSocketAcceptor繫結到一個具體的地址上。
繫結呼叫NioSocketAcceptor的bind方法,傳入一個或者一組地址。NioSocketAcceptor會啟動一個名字叫Acceptor的執行緒來完成繫結工作。繫結的過程簡單來說就是開一個ServerSocketChannel,然後把它與Selector關聯起來,用來接收連線請求。這個執行緒會一直執行,直到被取消繫結為止。每次呼叫bind方法,都會開這麼一個執行緒,所有的執行緒都被放到一個執行緒池裡面執行,這個執行緒池用的是java Executor執行緒池框架,這些執行緒池共用一個Selector。
當有新的連線請求過來之後,也就是TCP的客戶端呼叫了NIOSocketConnector的connect方法之後,Acceptor執行緒會把這個請求轉換成一個NIOSession,然後新增到 NIOProcessor中。在預設情況下,Acceptor會首先從SimpleIoProcessorPool裡面選取一個NIOProcessor,然後呼叫這個NIOProcessor的add方法來把NIOSession新增到這個NIOProcessor中。這個過程NIOProcessor會啟動一個名叫Processor的執行緒來處理與這個NIOSession有關的所有IO操作。預設情況下,每個NIOProcessor會用呼叫Executors.newCachedThreadPool()來建立一個執行緒池,其中的每個執行緒都會執行一個Processor,而每個Processor又都會關聯到一個NIOSession。這個執行緒會在通訊被伺服器端或者客戶端主動關閉,或者滿足空閒條件的時候被終止。每一個NIOProcessor中管理的Session都共用同一個Selector。
mina支援用一個或者多個執行緒池來處理所有的IO請求,這個其實是通過設定SimpleProcessorPool裡面的IOProcessor陣列長度來實現的。因為每一個IOProcessor自己會維護一個執行緒池來處理所有的IO請求(每一次IO請求就是一個Session),如果把IOProcessor的陣列長度設定成1,就是用一個執行緒池來處理所有的IO請求,如果大於1,那麼就是用多個執行緒池來處理所有的IO請求。


客戶端的處理過程大致類似,也是通過IOProcessor處理和維護所有的IO請求,只不過少了bind這一步操作。