Mina相關的總結-好文轉載

原文地址:https://donaldhan.github.io/mina/2018/02/03/Mina%E6%80%BB%E7%BB%93.html

iteye 站點:https://www.iteye.com/category/368102

引言

Mina是一個網絡通信應用框架,是基於TCP/IP、UDP/IP協議棧的通信框架(當然,也可以提供JAVA 對象的序列化服務、虛擬機管道通信服務等),Mina 可以幫助我們快速開發高性能、高擴展性的網絡通信應用,Mina提供了事件驅動、異步(Mina的異步IO,默認使用的是JAVA NIO 作爲底層支持)操作的編程模型。Mina的相關組件有IoService,IoProcessor,IoFilter,IoHanler,IoBuffer。

上面文章中的Mina源碼爲Mina的2.0分支,當時的源碼版本爲2.0.16。

目錄

Mina Socket會話配置

NioSocketAcceptor構造是傳輸入的DefaultSocketSessionConfig參數實際上是初始化AbstractIoService的會話配置選項sessionConfig(IoSessionConfig)。會話配置IoSessionConfig主要是配置IoProcessor每次讀操作分配的buffer的容量,一般情況下,不用手動設置這個屬性,因爲IoProcessor經常會自動調整;設置空閒狀態IdleStatus(READER_IDLE,WRITER_IDLE 或 BOTH_IDLE)的空閒時間;UseReadOperation配置項用於優化客戶端的讀取操作,開啓這個選項對服務器應用無效,並可能引起內存泄漏,因此默認爲關閉狀態。SocketSessionConfig主要是配置Socket,這些屬性在java.net.Socket中都可以找到相似或類似的屬性,比如發送緩衝區大小,是否保活,地址是否可重用等。從AbstractSocketSessionConfig來看SocketSessionConfig的發送、接收緩衝區大小,是否保活,地址是否可重用等配置默認爲true。DefaultSocketSessionConfig構造時,發送和接受緩存區默認爲-1,所以在創建NioSocketAcceptor要配置發送和接收緩存區大小; DefaultSocketSessionConfig關聯一個parent父對象IoService,即配置的依附對象。#init方法初始化的parent父對象IoService,如果parent父對象爲IoService(SocketAcceptor), 則地址默認可重用,否則不可。

Mina 過濾鏈默認構建器

過濾器鏈IoFilterChain用Entry存放過濾器對,即每個過濾器IoFilter關聯一個後繼過濾器NextFilter。我們可以通過濾器名name或過濾器實例ioFilter或過濾器類型獲取相應的過濾器或過濾器對應的Entry。fireMessage*/exceptionCaught相關方法爲觸發IoHandler的相關事件,fireFilterWrite/Close觸發的是,會話的相關事件IoSession#write/close。 DefaultIoFilterChainBuilder用entries列表(CopyOnWriteArrayList)來管理過濾器;添加過濾器,移除過濾器,及判斷是否包含過濾器都是依賴於CopyOnWriteArrayList的相關功能。buildFilterChain方法是將默認過濾器鏈構建器的過濾器集合中的過濾器添加到指定的過濾鏈IoFilterChain上。DefaultIoFilterChainBuilder的過濾器EntryImpl中的getNextFilter並沒有實際作用,即無效,這就說明了DefaultIoFilterChainBuilder只用於在創建會話時,構建過濾器鏈。創建完畢後,對過濾器鏈構建器的修改不會影響到會話實際的過濾器鏈IoFilterChain(SocketFilterChain,DatagramFilterChain...)。

Mina 過濾器定義

IoFilter添加到過濾鏈時,一般以ReferenceCountingIoFilter包裝,添加到過濾鏈,init方法在添加到過濾鏈時,由ReferenceCountingIoFilter調用,所以可以在init方法初始化一些共享資源。如果過濾器沒有包裝成ReferenceCountingIoFilter,init方法將不會調用。然後調用onPreAdd通知過濾器將會添加到過濾連上,當過濾器添加到過濾鏈上時,所有IoHandler事件和IO請求,將會被過濾器攔截當過濾器添加到過濾鏈上後,將會調用onPostAdd,如果方法有異常,過濾器在過濾鏈的鏈尾,ReferenceCountingIoFilter將調用#destroy方法釋放共享資源。過濾器IoFilter,主要是監聽會話IoSession相關事件(創建,打開,空閒,異常,關閉,接受數據,發送數據) 及IoSesssion的Write與close事件;過濾器後繼NextFilter關注的事件與過濾器IoFilter相同,主要是轉發相關事件。WriteRequest是會話IoSession寫操作write的包裝,內部有一個消息對象用於存放write的內容,一個socket地址,即會話寫請求的目的socket地址,一個寫請求結果返回值WriteFuture,用於獲取會話write消息的操作結果。當一個過濾器從過濾鏈上移除時,#onPreRemove被調用,用於通知過濾器將從過濾鏈上移除;如果過濾器從過濾鏈上移除,所有IoHandler事件和IO請求,過濾器不再攔截;#onPostRemove調用通知過濾器已經從過濾鏈上移除;移除後,如果過濾器在過濾鏈的鏈尾,ReferenceCountingIoFilter將調用#destroy方法釋放共享資源。

IoFilter生命週期如下: inti->onPreAdd->onPostAdd->(攔截IoHandler相關事件:sessionCreated,Opened,Idle,exceptionCaught,Closed,messageSent,messageReceived;會話相關事件:filterWrite,filterClose)->onPreRemove->onPostRemove->destroy。

Mina 日誌過濾器與引用計數過濾器

LoggingFilter攔截IoHandler的sessionCreated事件,將日誌輸出委託給SessionLog,然後將相關事件傳遞給過濾器後繼,攔截sessionOpened,sessionClosed, filterClose事件思路基本相同。對於sessionIdle,messageSent,messageReceived,filterWrite先判斷會話log的info級別是否開啓,開啓則輸出相應事件日誌。上面這些事件的日誌級別都是Info;exceptionCaught則先判斷會話log的warn級別是否開啓,開啓則輸出相應事件日誌。

一個過濾器可以多次添加到過濾鏈上,ReferenceCountingIoFilter用於保證過濾器第一次添加到過濾鏈上時,初始化過濾器,完全從過濾鏈上移除時,銷燬過濾器,釋放資;ReferenceCountingIoFilter內部一個count用於記錄包裝過濾器filter添加到過濾鏈上的次數,即過濾鏈上存在filter的個數,一個filter,即ReferenceCountingIoFilter包裝的過濾器,ReferenceCountingIoFilter觸發IoHandler和IoSession的相關事件,直接交給包裝的內部filter處理。

Mina 過濾鏈抽象實現

AbstractIoFilterChain內部關聯一個IoSession,用EntryImp來包裝過濾器,過濾鏈中用HashMap<String,EntryImpl>來存放過濾器Entry,key爲過濾器名,value爲過濾器Entry。EntryImpl是過濾器在過濾鏈上存在的形式,EntryImpl有一個前驅和一個後繼,內部包裹一個過濾器 with name,及過濾器的後繼過濾器NextFilter。後繼過濾器NextFilter的傳遞IoHandler和IoSession事件的方法,主要是將事件轉發給後繼Entry對應的過濾器。過濾鏈頭爲HeadFilter,鏈尾爲TailFilter。HeadFilter觸發IoHandler和IoSession事件時,將事件傳遞給後繼過濾器;但對於IoSession write/close事件除了傳遞事件外,需要調用實際的事件操作doWrite/doClose,這兩個方法需要子類擴展實現。TailFilter觸發IoHandler和IoSession事件時,直接調用會話處理器IoHandler的相關事件方法。在sessionOpened事件中,最後如果是SocketConnector創建的會話,則要通知相關ConnectFuture;在sessionClosed事件中,最後還要清空過濾鏈;messageSent和messageReceived事件,如果消息對象爲ByteBuffer,則釋放buffer。添加過濾器到過濾鏈,首先檢查過濾鏈上是否存在過濾器,不存在,才添加;添加過濾器到頭部即,插入過濾器到鏈頭的後面,添加過濾器到尾部,即插入過濾器到鏈尾的前面;添加到指定過濾器前後,思路基本相同;添加前觸發過濾器onPreAdd事件,添加後觸發過濾器onPostAdd事件;移除過濾器,首先獲取過濾器對應的Entry,然後觸發過濾器onPreRemove事件,從過濾鏈name2entry移除Entry,然後觸發過濾器onPostRemove事件。過濾鏈處理相關事件策略爲:與IoHanler的相關事件(Session*)處理的順序爲,從鏈頭到鏈尾-》Iohanlder(這個過程handler處理相關事件);對於會話相關的事件(FilterWrite/close),處理順序爲Iohanlder-》從鏈尾到鏈頭(這是會話事件,只是在handler的方法中使用會話發送消息,關閉會話,handler並不處理會話事件)。

Mina Socket與報文過濾鏈

SocketFilterChain發送消息首先獲取Socket會話的的寫請求隊列;mark buffer的位置,主要因爲buffer要傳給messageSent事件,待消息發送完成,SocketIoProcessor.doFlush方法將會reset buffer到當前mark的位置;根據buffer的實際數據容量來判斷是更新調度請求計數器還是更新調度寫字節計數器;將寫請求添加到session寫請求隊列中,如果session運行寫操作,獲取session關聯的IoProcessor完成實際的消息發送工作。關閉session,即將會話添加到關聯的IoProcessor待移除會話隊列。DatagramFilterChain發送消息首先獲取報文會話的的寫請求隊列;mark buffer的位置,主要因爲buffer要傳給messageSent事件,待消息發送完成,SocketIoProcessor.doFlush方法將會reset buffer到當前mark的位置;根據buffer的實際數據容量來判斷是更新調度請求計數器還是更新調度寫字節計數器;將寫請求添加到session寫請求隊列中,如果session允許寫操作,獲取session關聯的managerDelegate(DatagramService)完成實際的消息發送工作。 關閉會話委託給session關聯的managerDelegate(DatagramService),如果managerDelegate爲DatagramConnectorDelegate者直接關閉,如果爲DatagramAcceptorDelegate,通知DatagramAcceptorDelegate的監聽器會話已關閉,設置會話CloseFuture爲已關閉狀態。

Mina 協議編解碼過濾器一(協議編解碼工廠,協議編碼器)

協議編解碼過濾器ProtocolCodecFilter關聯一個協議編解碼工廠ProtocolCodecFactory,協議編解碼工廠提供協議編碼器ProtocolEncoder和解碼器ProtocolDecoder;編碼器將消息對象編碼成二進制或協議數據,解碼器將二進制或協議數據解碼成消息對象。編碼器ProtocolEncoder主要有兩個方法,encode和dispose;encode用於,編碼上層的消息對象爲二進制或協議數據。mina調用編碼器的#encode方法將從會話寫請求隊列中pop的消息,然後調用ProtocolEncoderOutput#write方法將編碼後的消息放在ByteBuffer;dispose方法釋放編碼器資源。ProtocolEncoderAdapter爲編碼器抽象實現,默認實現了dispose,不做任何事情,對於不需要釋放資源的編碼器繼承ProtocolEncoderAdapter。ProtocolEncoderOutput主要的工作是將協議編碼器編碼後的字節buffer,緩存起來,等待flush方法調用時,則將數據發送出去。SimpleProtocolEncoderOutput爲ProtocolEncoderOutput的簡單實現內部有一個buffer隊列bufferQueue(Queue),用於存放write(ByteBuffer)方法,傳入的字節buffer;mergeAll方法爲合併buffer隊列的所有buffer數據到一個buffer;flush方法爲發送buffer隊列中的所有buffer,實際發送工作委託給doFlush方法待子類實現。ProtocolEncoderOutputImpl爲協議編解碼過濾器的內部類,ProtocolEncoderOutputImpl的doFlush,首先將會話包裝成DefaultWriteFuture,將會話,寫請求信息傳遞給NextFilter。

Mina 協議編解碼過濾器二(協議解碼器)

解碼器ProtocolDecoder將二級制或協議內存解碼成上層消息對象。mina在讀取數據時,調用解碼器的#decode,將解碼後的消息放到ProtocolDecoderOutput;當會話關閉時,調用finishDecode解碼那些在#decode方法中沒有處理完的數據。dispose主要是 釋放所有與解碼器有關的資源。針對不需要#finishDecode和#dispose的解碼器,我們可以繼承協議解碼適配器ProtocolDecoderAdapter。ProtocolDecoderOutput有兩個方法,一個write方法,用於解碼器,解完消息後回調;一個flush方法,用於刷新所有解碼器寫到協議解碼輸出的消息對象。簡單協議解碼輸出SimpleProtocolDecoderOutput,關聯一個會話session,一個後繼過濾器nextFilter,及一個消息隊列messageQueue;所有解碼器解碼後的消息,回調協議解碼輸出的write方法,將消息暫時放在消息隊列messageQueue中;flush方法主要是將消息隊列中的消息傳給後繼過濾器的messageReceived方法。

Mina 隊列Queue

隊列Queue實際上爲List,用一個對象數組items存放元素,一個實際容量計數器size,一個隊頭first和一個隊尾索引last,默認隊列容量爲4。push元素時,先判斷隊列是否已滿,如果已滿,則擴容隊列爲原來的兩倍。Queue實際爲具有隊列特性的List。Queue可以隨機地訪問隊列索引。

Mina 協議編解碼過濾器三(會話write與消息接收過濾)

協議編解碼過濾器構造,主要是初始化協議編碼器工廠。一個過濾鏈上不能存在兩個協議編解碼器,即唯一。會話寫操作來看session#write(filterWrite),首先從寫請求獲取消息,如果消息爲字節buffer,則直接傳給後繼過濾器,否則從協議編解碼工廠獲取協議編碼器和協議編碼器輸出,協議編碼器encode編碼消息,寫到協議編碼器輸出字節buffer隊列, 然後協議編碼器輸出flush字節buffer隊列。會話接收消息messageReceived,如果消息非字節buffer,則直接傳給後繼過濾器,否則獲取協議解碼器,及協議解碼器輸出,協議解碼器解碼字節buffer爲上傳消息對象,寫到協議解碼器輸出消息隊列,最後解碼器輸出flush消息隊列。會話關閉,主要是解碼器解碼會話未解碼數據,寫到解碼器輸出消息隊列,最後從會話移除編碼器,解碼器及解碼器輸出屬性,釋放編碼器,解碼器及解碼器輸出相關資源,flush解碼器輸出消息隊列。協議編解碼器過濾器從過濾鏈移除後,要釋放會話編解碼器,及解碼輸出屬性,並釋放相關的資源。

Mina 累計協議解碼器

累積性協議解碼器decode方法,首先從會話獲取屬性BUFFER對應的buffer,如果會話緩存buffer不爲null,則將當前in(ByteBuffer)的內容放到會話緩存buffer中;否直接使用當前in(ByteBuffer),將是否開啓會話緩存buffer,置爲否;循環嘗試使用doDecode方法解碼數據,直到doDecode方法返回false,如果doDecode方法返回true,則繼續調用doDecode方法解碼數據,如果在一次解碼數據返回true,但buffer中還有數據,則根據是否開啓會話緩存buffer決定將buffer數據進行壓縮還是存儲在會話中;如果在一次解碼數據返回true,但buffer中沒有數據,則從會話中移除屬性BUFFER,並釋放對應的buffer空間。doDecode方法放抽象方法待類型實現。CumulativeProtocolDecoder實現可累性方法主要是通過將buffer存儲在會話中,以實現接收數據的可累計性

MINA 多路複用協議編解碼器工廠一(多路複用協議編碼器)

多路複用的協議編碼器添加消息編碼器,如果參數爲消息類型和消息編碼器類型,添加消息類型與默認構造消息編碼工廠到消息編碼器Map映射type2encoderFactory;如果參數爲消息類型和消息編碼器實例,添加消息類型與單例消息編碼器工廠到消息編碼器Map映射type2encoderFactory。多路複用的協議編碼器編碼消息,首先從會話獲取消息編碼器狀態,從消息編碼器狀態獲取消息對應的編碼器(先從消息編碼器查找,沒有則從消息編碼器映射type2encoder查找),如果沒有消息對應的解碼,則查找消息父接口和類對應的編碼器,編碼消息。

MINA 多路複用協議編解碼器工廠二(多路複用協議解碼器)

消息解碼器MessageDecoder,有3個方法分別爲,decodable方法用於判斷解碼器是否可以解碼buffer數據,返回值(MessageDecoderResult)#OK表示可以解碼buffer中的數據,#NOT_OK表示解碼器不可解碼buffer數據, #NEED_DATA表示需要更多的數據來確認解碼器是否可以解碼buffer數據;decode用於解碼buffer數據,返回值#OK表示解碼消息成功,#NEED_DATA,表示需要更多的數據完成消息解碼,#NOT_OK由於內容與協議不一致,不能解碼當前消息;finishDecode主要是處理#decode方法沒有解碼完的數據。添加解碼器到多路複用協議解碼器,如果添加的解碼器爲Class,則添加默認構造消息解碼器工廠到到多路複用協議解碼器工廠集decoderFactories;如果添加的解碼器爲實例,則添加單例解碼器工廠,到多路複用協議解碼器工廠集。多路複用協議解碼器,解碼消息的過程爲,首先從會話獲取解碼器狀態集,遍歷解碼器集,找到可以解碼消息的解碼器,並賦給會話解碼器狀態當前解碼器currentDecoder,最後由currentDecoder解碼消息。 多路複用協議編解碼器工廠內部關聯一個多路複用協議編碼器和解碼器器,添加消息編碼器和解碼器到多路複用協議編解碼器工廠,實際是添加多路複用協議編解碼器中。

Mina Io處理器抽象實現

抽象Io處理器AbstractPollingIoProcessor,主要幾個關鍵內部變量爲選擇操作超時時間SELECT_TIMEOUT,用於騰出時間,處理空閒的會話; executor處理器內部執行器,用於運行內部處理器Processor;存儲Io處理器等線程最大線程id的threadIds(Map);創建會話隊列newSessions用於存儲新創建的會話;移除會話隊列removingSessions用於存放從處理器移除的會話;刷新會話隊列flushingSessions,用於存放要發送寫請求的會話;次序控制會話隊列trafficControllingSessions用於存放會話待讀寫的會話;Io處理器線程引用processorRef。 添加會話首先添加會話到Io處理器的創建會話隊列中,啓動處理器線程Processor。處理器的實際工作,嘗試10次nbTries選擇操作,在每次選擇操作過程中,首先進行超時選擇操作,然後檢查Io處理器是否斷開連接,嘗試次數nbTries是否爲零如果爲0,則註冊新的選擇器;然後遍歷創建會話隊列,從隊列拉取會話,如果會話爲不null,則初始化會話,構建會話過濾鏈(從IoService繼承)觸發會話過濾鏈的會話創建和會話打開事件,並記錄新創建的會話數量nSessions;更會會話狀態,此過程爲從會話次序控制隊列獲取會話,檢查會話狀態,如果狀態爲OPENED更新會話的讀寫狀態,如果爲OPENING放回次序控制會話隊列;如果選擇操作返回的SELECTKey的值大於0,即有相關的興趣操作事件(讀寫事件),遍歷選擇後讀寫等操作就緒的會話,如果會話可讀,則讀取會話緩存區數據到buffer,觸發過濾鏈消息接收事件MessageReceive,接收完消息後,如果會話輸入流關閉則觸發過濾鏈fireInputClosed事件,如果在這過程有異常發生,則觸發過濾鏈異常事件ExceptionCaught,如果會話可寫,則添加會話到刷新會話隊列;遍歷刷新會話隊列,根據會話寫請求消息類型爲IoBuffer還是FileRegion,發送會話數據,發送會話數據後,如果會話還有些請求,則添加會話到隊列,如果在這個過程中有異常,則添加會話到會話移除隊列;遍歷會話移除隊列,如果會話爲關閉,則嘗試關閉會話,並清除會話寫請求隊列,如果會話數據已發送完,則觸發會話過濾鏈消息發送事件fireMessageSent;更新處理器會話計數器nSessions;遍歷處理器所有會話,觸發會話過濾器會話空閒時間fireSessionIdle;如果在這個過程中,處理器會話計數器nSessions爲0,則清除處理器引用;如果Io處理器正在關閉,則添加所有會話到移除會話隊列,釋放Io處理器先關的資源。 抽象Io處理器AbstractPollingIoProcessor主要是處理IoProcessor關聯會話message*事件,而所有的工作,都是通過處理器線程Processor完成。每當有會話添加到IoProcessor,則啓動一個處理器線程Processor,處理會話的讀寫操作及相關事件。就連IoProcessor資源的釋放,也是由處理器線程Processor處理。關閉IoProcessor時,現將處理器關聯會話,添加移除會話隊列,實際工作由IoProcessor的子類的doDispose方法完成。

Mina Nio處理器

NioProcessor內部有一個選擇器Selector,一個可重入讀寫鎖用於控制選擇器相關的操作,構造主要是初始化線程執行器和選擇器。Nio處理器的選擇操作,喚醒等操作,實際通過內部的選擇器完成。初始化會話,主要是配置會話通道爲非阻塞模式,註冊會話通道讀事件到選擇器。註冊新選擇器,主要是註冊舊選擇器的選擇key(集合)關聯的會話,通道,及通道興趣事件集到新的選擇器;會話時附加在通道選擇key的Attachment上。處理器處理會話讀寫操作,主要是通過會話關聯的通道完成。關閉會話主要是關閉會話關聯的字節通道和取消會話關聯選擇key。

Mina 抽象Io會話

抽象會話AbstractIoSession內部有一個關聯的IoService和一個IoHandler;一個寫請求隊列用於存發會話寫請求;一個會話屬性Map存放會話屬性,還有一些讀寫字節數,消息數,相關吞吐量和上次讀寫或空閒操作時間計數器。,會話初始化主要爲初始化關聯service,及關聯的IoHandler,實際爲Service的IoHandler;初始化所有的會話事件計數器爲當前時間。關閉方法默認關閉時,清空寫請求隊列,並將寫請求的結果置爲已寫,觸發過濾過濾鏈fireFilterClose事件,即不flush會話寫請求隊列,closeOnFlush方法爲,在關閉會話前,flush會話寫請求隊列。會話讀操作,首先獲取會話讀請求結果隊列,從隊列poll一個讀結果,如果讀結果不爲空且已關閉,則重新入隊列,否則新建一個默認讀請求結果,添加到會話等待讀請求結果隊列。會話寫請求,首先保證消息不爲null,會話建立連接,並且遠端socket地址不爲null;如果消息爲IoBuffer,確保buffer不爲空,如果消息爲文件通道/文件類型,則包裝消息爲DefaultFileRegion/FilenameFileRegion;然後創建寫請求DefaultWriteRequest,觸發會話過濾鏈fireFilterWrite事件,如果消息爲文件通道,則註冊寫結果監聽器,在消息發送完後,關閉文件通道,返回寫結果DefaultWriteFuture。

Mina Nio會話(Socket,DataGram)

NioSession會話主要管理會話關聯Io處理器processor,通道channel,選擇鍵SelectionKey和會話過濾鏈IoFilterChain;IoService交由AbstractIoSession管理。 socket會話NioSocketSession配置繼承於關聯IoService的會話配置 ;關閉會話,即取消會話關聯的選擇key和關閉關聯通道。

Mina IoService接口定義及抽象實現

抽象service關聯一個IoHandler處理會話相關事件,關聯一個執行器Executor,負責處理io事件的執行,一個會話配置IOsessionConfig,用於service創建會話時,配置會話,一個過濾鏈構建器IoFilterChainBuilder,用於構建會話的過濾鏈,會話數據結構工廠,用於創建會話的屬性Map和寫請求隊列,還有service監聽器和統計器。抽象service構造,首先檢查會話配置和傳輸元數據,會話配置必須傳輸元數據的會話配置類型必須相同,即socket(TCP),會話配置爲socketSessionConfig,報文通信(UDP),爲DatagramSessionConfig;然後將會話創建監聽器serviceActivationListener添加監聽器管理器IoServiceListenerSupport;初始化會話配置,IO事件執行器executor和異常監視器。初始化會話就是將service會話數據結構工廠的會話屬性添加到具體的會話中,將service會話數據結構工廠的寫請求隊列,設置到具體的會話中,如果是連接請求會話,則將連接結果添加會話屬性中。

Mina Io監聽器接口定義及抽象實現

IoAcceptor與IoService不同的是,添加了監聽連接請求和地址綁定功能。抽象Io監聽器AbstractIoAcceptor綁定地址首先要檢查綁定的socket地址與傳輸元數據的地址類型是否相同,相同則通過bindInternal完成實際的綁定,然後通知Service監聽器,Service已激活fireServiceActivated。解綁地址方法,主要是委託unbind0方法完成實際解綁工作,清空綁定地址集合boundAddresses,觸發Service監聽器無效事件fireServiceDeactivated。

Mina 抽象polling監聽器

AbstractPollingIoAcceptor主要變量爲Io處理器processor,地址綁定請求隊列registerQueue,地址解綁請求隊列cancelQueue,監聽器綁定的socket地址,與ServerSocketChannel映射關係boundHandles-Map,監聽工作線程Acceptor引用acceptorRef。

構造AbstractPollingIoAcceptor,主要是初始化會話配置,Io處理器類型,IO異步事件執行器爲空的話默認爲CachedThreadPool,然後初始化選擇器。地址綁定過程爲,創建綁定操作結果,註冊綁定請求到註冊地址綁定請求隊列,創建監聽器Acceptor實例並執行。Acceptor主要功能爲,地址綁定,監聽連接請求,解綁地址,實際工作邏輯爲:如果監聽器AbstractPollingIoAcceptor已經初始化,首先根據地址綁定隊列中的綁定請求,打開一個ServerSocketChannle,註冊接收事件OP_ACCEPT到選擇器,並將綁定地址與ServerSocketChannle映射管理添加到地址綁定映射集合;執行選擇操作,如果實際綁定地址爲空,則置空acceptorRef;如果接收連接事件發生,則處理連接請求,遍歷接收事件就緒的ServerSocketChannel,ServerSocketChannel創建一個關聯processor的會話,初始化會話,添加會話到會話關聯io處理器;檢查是否有地址解綁請求,如果有解綁請求CancellationRequest,從綁定socket地址與ServerSocketChannle映射map中,移除綁定的socket地址,關閉ServerSocketChannle;最後檢查監聽器是否正在關閉,如果acceptor正在關閉,則關閉關聯processor。Acceptor和AbstractPollingIoAcceptor的關係,與AbstractPollingIoProcessor和Processor的關係很像。地址解綁過程,首先根據解綁地址創建AcceptorOperationFuture,添加到解綁隊列,啓動Acceptor線程,完成實際解綁工作。AbstractPollingIoAcceptor所有的工作(地址綁定,接收連接,創建會話,添加會話到IO處理器,解綁地址,釋放監聽器資源)都是在Acceptor線程裏完成。

Mina socket監聽器(NioSocketAcceptor)

socket監聽NioSocketAcceptor,有兩個內部變量爲選擇器selector和選擇器提供者selectorProvider。init方法主要工作爲打開一個選擇器selector。打開一個socket地址,如果選擇器提供者不爲空,則通過選擇器提供者打開一個ServerSocketChannel,否則通過ServerSocketChannel打開一個socket通道服務者;配置通道阻塞模式,及通道關聯的SeverSocket的地址重用配置,然後通過SeverSocket綁定地址。監聽器接受連接,實際上是委託給綁定地址的ServerSocketChannel,接受客戶端的連接,產生一個SocketChannel,再根據SocketChannel和Io處理器創建會話。選擇喚醒操作實際委託給內部選擇器。

Mina 連接器接口定義及抽象實現(IoConnector)

IoConnector接口給Ioservice增加了連接功能,可以連接服務端。連接操作,首先檢查連接器狀態,本地地址與遠程地址是否爲空已經與傳輸元數據地址類型是否匹配,如果連接器Iohandler爲null,創建一個對會話操作事件不處理的IoHandler,最後將實際連接操作委託給connect0,待子類實現。

Mina 抽象Polling連接器(AbstractPollingIoConnector)

抽象拉取連接器內部有一個連接請求隊列connectQueue,連接請求取消隊列cancelQueue,Io處理器和連接線程引用connectorRef。拉取連接器構造主要初始化會話配置,IO事件執行器和IO處理器。連接操作,首先根據本地socket地址創建SocketChannel,連接遠端socket地址,根據IO處理器和SocketChannel構建Io會話,將會話添加到會話關聯的IO處理器中,根據SocketChannel和會話初始化sessionInitializer構建連接請求,添加到連接請求隊列,最後啓動連接器線程。連接器線程首先計算選擇超時時間,執行超時選擇操作,註冊連接請求SocketChannel連接事件到選擇器;如果沒有任何連接請求SocketChannel需要處理,置空連接器連接線程引用,清空連接請求隊列,如果有連接請求已經連接完成,即觸發SocketChannel興趣連接事件,處理連接事件就緒的連接請求,這個過程首先調用finishConnect完成SocketChannel連接後續工作,根據Io處理器和SocketChannel創建會話,初始化會話,添加會話到會話關聯的IO處理器;然後處理連接超時的連接請求,即設置連接結果超時異常,添加到連接請求到取消隊列;處理取消連接的連接請求,即關閉連接請求關聯的SocketChannel。

Mina socket連接器(NioSocketConnector)

socket連接器NioSocketConnector內部關聯一個選擇器;初始化連接器,爲打開一個選擇器;連接遠端地址,即委託SocketChannel的連接操作;創建socket通道來看,首先打開一個socket通道,配置接收緩存區size,綁定本地socket地址,配置通道爲非阻塞模式;註冊操作,即註冊socket通道的連接事件到選擇器。選擇操作和喚醒操作直接委託給內部選擇器。銷燬socket連接器,即關閉選擇器。

Mina 報文監聽器NioDatagramAcceptor一(初始化,Io處理器)

報文監聽器NioDatagramAcceptor,內部有一個註冊隊列registerQueue,用於存放地址綁定的請求,一個取消隊列,用於存放地址解綁請求,一個Map-boundHandles,用於存放socket地址與報文通道映射映射關係,會話管理器sessionRecycler,監控連接Service的會話,如果會話過期,關閉過期的會話,一個通道選擇器selector處理報文通道的讀寫操作事件,一個監聽器線程acceptor,用於處理地址綁定和解綁,報文通道讀寫事件,發送會話消息及銷燬監聽器工作。報文監聽器構造主要是初始化會話配置,IO事件執行器和打開選擇器。報文監聽器寫操作,首先獲取會話寫請求隊列,計算會話最大發送字節數,獲取會話寫請求buffer;如果寫請求爲空,則從請求隊列poll一個寫請求,然後獲取寫請求buffer及寫請求目的socket地址,委託會話關聯的報文通道發送數據;如果buffer數據太多或沒有寫成功,添加寫請求到會話請求隊列,關注寫事件,否則取消關注寫事件,置空會話當前寫請求,觸發會話發送事件。綁定地址,首先添加地址綁定請求到註冊隊列registerQueue,啓動監聽器線程acceptor,喚醒選擇操作,然後等待地址綁定完成,最後返回報文通道綁定的socket地址集。

Mina 報文監聽器NioDatagramAcceptor二(發送會話消息據等)

監聽器線程Acceptor,首先執行超時選擇操作;處理地址綁定請求,首先從註冊隊列poll地址綁定請求,遍歷綁定請求地址集,根據綁定的socket地址打開一個報文通道,配置通道會話及阻塞模式,綁定socket地址,註冊報文通道讀操作事件OP_READ到選擇器selector,添加socket地址與報文通道映射到boundHandles,通知service監聽,服務已開啓,觸發fireServiceActivated事件; 如果沒有報文通道處理,則清空註冊隊列和取消隊列,置空監聽器線程; 如果選擇操作後,有報文通道的讀寫事件就緒,則遍歷讀寫操作事件就緒的報文通道,如果是讀事件,接受報文通道數據,如果遠端地址不爲空,創建會話,首先從boundHandles獲取遠端socket地址關聯的報文通道,從會話管理器sessionRecycler,獲取遠端socket地址會話,以便重用,如果會話管理器中不存在,則根據Io處理器,報文通道及遠端socket地址創建報文會話,設置會話選擇key,將會話添加會話管理器,監控會話,初始化會話,構建會話過濾鏈,通知Service監聽器發生會話創建事件fireSessionCreated;如果是寫事件,則調度Service管理的會話,添加到刷新隊列; 處理刷新隊列,從刷新隊列poll寫請求會話,獲取會話寫請求隊列,會話最大讀buffer size,獲取會話當前寫請求,獲取寫請求消息,寫請求遠端地址,通過會話關聯的報文通道發送會話消息字節序列,數據發送成功,置空會話當前寫請求,觸發會話過濾鏈消息發送事件fireMessageSent,否則設置會話重新關注寫操作事件,如果刷新會話寫請求成功,但會話寫請求隊列不爲空,且未調度,則重新調度會話;處理解綁地址請求隊列,首先從取消隊列,poll地址解綁請求,遍歷地址解綁請求socket地址集合,從socket與報文通道映射集boundHandles移除socket地址,關閉報文通道;通知service管理的會話空閒;如何Io處理器正在關閉,則銷燬報文監聽器。

Mina 報文連接器(NioDatagramConnector)

由於報文連接器是面向無連接的,與選擇器有關的操作要麼不支持,要麼空體,要麼返回空集合;連接操作直接委託報文通道;綁定地址,首先打開一個報文通道,然後由報文通道關聯的報文socket完成實際的地址綁定。

總結

socket監聽器和連接器關聯一個選擇器selector和Io處理器processor,Io處理器processor處理所有的IO事件,當有連接請求時創建會話,IO會話關聯一個Io處理器processor,通道channel,選擇鍵SelectionKey和會話過濾鏈IoFilterChain。會話相關的事件,經過過濾鏈過濾,與IoHanler的相關事件(Session*)處理的順序爲,從鏈頭到鏈尾-》Iohanlder(這個過程handler處理相關事件);對於會話相關的事件(FilterWrite/close),處理順序爲Iohanlder-》從鏈尾到鏈頭(這是會話事件,只是在handler的方法中使用會話發送消息,關閉會話,handler並不處理會話事件)。Mina中的消息編碼器和解碼器是以編輯器工廠過濾器的形式存在於過濾鏈上。通道IoHandler處理會話的讀寫等操作。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章