一:mina屏蔽了網絡通信的一些細節,對sokcet進行封裝,並且是NIO的一個實現框架,可以幫助我們快速的開發網絡通信,
1.1:mima的工程流程
IOService接口
用戶描述我們的客戶端可服務端接口,其子類是connector和acceptor,分別用於描述我們的客戶端和服務端IOproceser多線程環境來處理我們的連接請求流程
ioFilter提供數據的過來工作,包括編碼,解碼,日誌等信息的過濾
Hanlder就是我們的業務對象,自定義的hanlder需要實現IOHandlerAcceptor。
1.2:mina的類結構
IOService :描述的是客戶端和服務端連接的描述,常常用戶接受和發送數據
1.2.1:執行過程
:
1.2.2:設計到的類
NIOSocketAcceptor 通信管理
IOseeeion :session管理
IoService:這個接口在一個線程上負責套接字的建立,擁有自己的Selector,監聽是否有連接被建立。
IoProcessor:這個接口在另一個線程上,負責檢查是否有數據在通道上讀寫,也就是說它也擁有自己的Selector,這是與我們使用JAVA NIO 編碼時的一個不同之處,通常在JAVA NIO 編碼中,我們都是使用一個Selector,也就是不區分IoService與IoProcessor 兩個功能接口。另外,IoProcessor 負責調用註冊在IoService 上的過濾器,並在過濾器鏈之後調用IoHandler。
IoFilter:這個接口定義一組攔截器,這些攔截器可以包括日誌輸出、黑名單過濾、數據的編碼(write 方向)與解碼(read 方向)等功能,其中數據的encode 與decode是最爲重要的、也是你在使用Mina 時最主要關注的地方。
IoHandler:這個接口負責編寫業務邏輯,也就是接收、發送數據的地方。
二:mina的長短連接
長連接:
客戶端和服務端保持一個長時間連接狀態, 所謂長連接,指在一個TCP連接上可以連續發送多個數據包,在TCP連接保持期間,如果沒有數據包發送,需要雙方發檢測包以維持此連接,一般需要自己做在線維持(不發生RST包和四次揮手)。
短連接:
短連接是指通信雙方有數據交互時,就建立一個TCP連接,數據發送完成後,則斷開此TCP連接(管理起來比較簡單,存在的連接都是有用的連接,不需要額外的控制手段);
三:IOService接口介紹
3.1:IOService:
3.1.1: IOService 實現了網絡通信額客戶端和服務端之間的抽象,用於描述客戶端額子接口IOConnector,用於描述服務端IOAcceptor
:3.1.2: IOService可以管理我們網絡通信的客戶端和服務端,並且可以管理雙方回話,session同樣可以添加過濾器。
3.1.3:IOService的類結構
通過擴展子接口和抽象子類達到擴展額目的
(1.)IoService:
這個接口是服務端 IoAcceptor、客戶端 IoConnector 的抽象,提供 IO 服務和管理 IoSession 的功能,它有如下幾個常用的方法:
-
- TransportMetadata getTransportMetadata():
這個方法獲取傳輸方式的元數據描述信息,也就是底層到底基於什麼的實現,譬如:nio、apr 等。
-
- void addListener(IoServiceListener listener):
這個方法可以爲 IoService 增加一個監聽器,用於監聽 IoService 的創建、活動、失效、空閒、銷燬,具體可以參考 IoServiceListener 接口中的方法,這爲你參與 IoService 的生命週期提供了機會。
-
- void removeListener(IoServiceListener listener):這個方法用於移除上面的方法添加的監聽器。
-
- void setHandler(IoHandler handler):
這個方法用於向 IoService 註冊IoHandler,同時有 getHandler()方法獲取Handler。
-
- Map<Long,IoSession> getManagedSessions():
這個方法獲取 IoService 上管理的所有 IoSession,Map 的 key 是IoSession 的 id。
-
- IoSessionConfig getSessionConfig():
這個方法用於獲取 IoSession 的配置對象,通過 IoSessionConfig 對象可以設置 Socket 連接的一些選項。
(2.)IoAcceptor:
這個接口是 TCPServer 的接口,主要增加了 void bind()監聽端口、void unbind()解除對套接字的監聽等方法。這裏與傳統的 JAVA 中的 ServerSocket 不同的是 IoAcceptor 可以多次調用 bind()方法(或者在一個方法中傳入多個 SocketAddress 參數)同時監聽多個端口。
(3.)IoConnector:
這個接口是 TCPClient 的接口, 主要增加了 ConnectFuture connect(SocketAddress remoteAddress,SocketAddress localAddress)方法,用於與 Server 端建立連接,第二個參數如果不傳遞則使用本地的一個隨機端口訪問 Server 端。這個方法是異步執行的,同樣的, 也可以同時連接多個服務端。
(4.)IoSession:
這個接口用於表示 Server 端與 Client 端的連接,IoAcceptor.accept()的時候返回實例。這個接口有如下常用的方法:
- WriteFuture write(Object message):
這個方法用於寫數據,該操作是異步的。
- CloseFuture close(boolean immediately):
這個方法用於關閉 IoSession,該操作也是異步的,參數指定 true 表示立即關閉,否則就在所有的寫操作都 flush 之後再關閉。
- Object setAttribute(Object key,Object value):
這個方法用於給我們向會話中添加一些屬性,這樣可以在會話過程中都可以使用,類似於HttpSession 的 setAttrbute()方法。IoSession 內部使用同步的 HashMap 存儲你添加的自定義屬性。
- SocketAddress getRemoteAddress():這個方法獲取遠端連接的套接字地址。
- void suspendWrite():
這個方法用於掛起寫操作,那麼有 void resumeWrite()方法與之配對。對於 read()方法同樣適用。
- ReadFuture read():
這個方法用於讀取數據, 但默認是不能使用的, 你需要調用 IoSessionConfig 的setUseReadOperation(true)纔可以使用這個異步讀取的方法。一般我們不會用到這個方法, 因爲這個方法的內部實現是將數據保存到一個 BlockingQueue,假如是 Server 端,因爲大量的 Client 端發送的數據在 Server 端都這麼讀取,那麼可能會導致內存泄漏,但對於Client,可能有的時候會比較便利。
- IoService getService():
這個方法返回與當前會話對象關聯的 IoService 實例。
四:自定義過濾器
前面我們看到了 LoggingFilter、ProtocolCodecFilter 兩個過濾器,一個負責日誌輸出, 一個負責數據的編解碼,通過最前面的 Mina 執行流程圖,在 IoProcessor 與IoHandler 之間可以有很多的過濾器,這種設計方式爲你提供可插拔似的擴展功能提供了非常便利的方式,目前的 Apache CXF、Apache Struts2 中的攔截器也都是一樣的設計思路。
Mina 中的 IoFilter 是單例的,這與 CXF、Apache Struts2 沒什麼區別。IoService 實例上會綁定一個 DefaultIoFilterChainBuilder 實例,
DefaultIoFilterChainBuilder 會把使用內部的EntryImpl 類把所有的過濾器按照順序連在一起,組成一個過濾器鏈。
DefaultIoFilterChainBuilder 類如下常用的方法:
- void addFirst(String name,IoFilter filter):
這個方法把過濾器添加到過濾器鏈的頭部,頭部就是 IoProcessor 之後的第一個過濾器。同樣的 addLast()方法把過濾器添加到過濾器鏈的尾部。
- void addBefore(String baseName,String name,IoFilter filter):
這個方法將過濾器添加到baseName 指定的過濾器的前面,同樣的 addAfter()方法把過濾器添加到 baseName 指定的過濾器的後面。這裏要注意無論是那種添加方法,每個過濾器的名字(參數 name)必須是唯一的。
- IoFilter remove(Stirng name):
這個方法移除指定名稱的過濾器,你也可以調用另一個重載的 remove()方法,指定要移除的 IoFilter 的類型。
- List<Entry> getAll():
這個方法返回當前 IoService 上註冊的所有過濾器。
默認情況下,過濾器鏈中是空的,也就是getAll()方法返回長度爲 0 的 List,但實際 Mina 內部有兩個隱藏的過濾器:HeadFilter、TailFilter,分別在List 的最開始和最末端,很明顯,TailFilter 在最末端是爲了調用過濾器鏈之後,調用 IoHandler。但這兩個過濾器對你來說是透明的,可以忽略它們的存在。
編寫一個過濾器很簡單,你需要實現 IoFilter 接口,如果你只關注某幾個方法,可以繼承IoFilterAdapter 適配器類。IoFilter 接口中主要包含兩類方法,一類是與 IoHandler 中的方法名一致的方法,相當於攔截 IoHandler 中的方法,另一類是 IoFilter 的生命週期回調方法,這些回調方法的執行順序和解釋如下所示:
(1.)init()在首次添加到鏈中的時候被調用,但你必須將這個 IoFilter 用 ReferenceCountingFilter 包裝起來,否則 init()方法永遠不會被調用。(2.)onPreAdd()在調用添加到鏈中的方法時被調用,但此時還未真正的加入到鏈。 (3.)onPostAdd()在調用添加到鏈中的方法後被調,如果在這個方法中有異常拋出,則過濾器會立即被移除,同時 destroy()方法也會被調用(前提是使用 ReferenceCountingFilter 包裝)。
(4.)onPreRemove()在從鏈中移除之前調用。 (5.)onPostRemove()在從鏈中移除之後調用。
(6.)destory()在從鏈中移除時被調用,使用方法與init()要求相同。
無論是哪個方法,要注意必須在實現時調用參數 nextFilter 的同名方法,否則,過濾器鏈的執行將被中斷,IoHandler 中的同名方法一樣也不會被執行,這就相當於 Servlet 中的Filter 必須調用 filterChain.doFilter(request,response)才能繼續前進是一樣的道理。
在handler處理之前,需要調用相應的
五:IOSession
這個接口用於表示 Server 端與 Client 端的連接,IoAcceptor.accept()的時候返回實例。這個接口有如下常用的方法:
- WriteFuture write(Object message):
這個方法用於寫數據,該操作是異步的。
- CloseFuture close(boolean immediately):
這個方法用於關閉 IoSession,該操作也是異步的,參數指定 true 表示立即關閉,否則就在所有的寫操作都 flush 之後再關閉。
- Object setAttribute(Object key,Object value):
這個方法用於給我們向會話中添加一些屬性,這樣可以在會話過程中都可以使用,類似於HttpSession 的 setAttrbute()方法。IoSession 內部使用同步的 HashMap 存儲你添加的自定義屬性。
- SocketAddress getRemoteAddress():這個方法獲取遠端連接的套接字地址。
- void suspendWrite():
這個方法用於掛起寫操作,那麼有 void resumeWrite()方法與之配對。對於 read()方法同樣適用。
- ReadFuture read():
這個方法用於讀取數據, 但默認是不能使用的, 你需要調用 IoSessionConfig 的setUseReadOperation(true)纔可以使用這個異步讀取的方法。一般我們不會用到這個方法, 因爲這個方法的內部實現是將數據保存到一個 BlockingQueue,假如是 Server 端,因爲大量的 Client 端發送的數據在 Server 端都這麼讀取,那麼可能會導致內存泄漏,但對於Client,可能有的時候會比較便利。
- IoService getService():
這個方法返回與當前會話對象關聯的 IoService 實例。
IoSessionConfig:
這個方法用於指定此次會話的配置,它有如下常用的方法:
- void setReadBufferSize(int size):
這個方法設置讀取緩衝的字節數,但一般不需要調用這個方法,因爲 IoProcessor 會自動調整緩衝的大小。你可以調用 setMinReadBufferSize()、setMaxReadBufferSize()方法,這樣無論 IoProcessor 無論如何自動調整,都會在你指定的區間。
- void setIdleTime(IdleStatus status,int idleTime):
這個方法設置關聯在通道上的讀、寫或者是讀寫事件在指定時間內未發生,該通道就進入空閒狀態。一旦調用這個方法,則每隔idleTime 都會回調過濾器、IoHandler 中的sessionIdle() 方法。
- void setWriteTimeout(int time):這個方法設置寫操作的超時時間。
- void setUseReadOperation(boolean useReadOperation): 這個方法設置 IoSession 的 read()方法是否可用,默認是 false。
六:線程模型