Apache Mina Server 2.0 中文參考手冊 【筆記】

#Apache Mina Server 2.0 中文參考手冊
##3. 介紹Mina的TCP的主要接口:java

###(1.)IoService:
這個接口是服務端IoAcceptor、客戶端IoConnector 的抽象,提供IO 服務和管理IoSession 的功能,它有以下幾個經常使用的方法:緩存

A. TransportMetadata getTransportMetadata():

這個方法獲取傳輸方式的元數據描述信息,也就是底層到底基於什麼的實現,譬如:nio、 apr 等。安全

B. void addListener(IoServiceListener listener):

這個方法能夠爲IoService 增長一個監聽器,用於監聽IoService 的建立、活動、失效、空 閒、銷燬,具體能夠參考IoServiceListener 接口中的方法,這爲你參與IoService 的生命 週期提供了機會。session

C. void removeListener(IoServiceListener listener):

這個方法用於移除上面的方法添加的監聽器。異步

D. void setHandler(IoHandler handler):

這個方法用於向IoService 註冊IoHandler,同時有getHandler()方法獲取Handler。ide

E. Map<Long,IoSession> getManagedSessions():

這個方法獲取IoService 上管理的全部IoSession,Map 的key 是IoSession 的id。性能

F. IoSessionConfig getSessionConfig():

這個方法用於獲取IoSession 的配置對象,經過IoSessionConfig 對象能夠設置Socket 連 接的一些選項。ui


###(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()的時候返回實例。 這個接口有以下經常使用的方法:

A. WriteFuture write(Object message):

這個方法用於寫數據,該操做是異步的。

B. CloseFuture close(boolean immediately):

這個方法用於關閉IoSession,該操做也是異步的,參數指定true 表示當即關閉,不然就 在全部的寫操做都flush 以後再關閉。

C. Object setAttribute(Object key,Object value):

這個方法用於給咱們向會話中添加一些屬性,這樣能夠在會話過程當中均可以使用,相似於 HttpSession 的setAttrbute()方法。IoSession 內部使用同步的HashMap 存儲你添加的自 定義屬性。

D. SocketAddress getRemoteAddress():

這個方法獲取遠端鏈接的套接字地址。

E. void suspendWrite():

這個方法用於掛起寫操做,那麼有void resumeWrite()方法與之配對。對於read()方法同 樣適用。

F. ReadFuture read():

這個方法用於讀取數據, 但默認是不能使用的, 你須要調用IoSessionConfig 的 setUseReadOperation(true)纔可使用這個異步讀取的方法。通常咱們不會用到這個方法, 由於這個方法的內部實現是將數據保存到一個BlockingQueue,假如是Server 端,由於大 量的Client 端發送的數據在Server 端都這麼讀取,那麼可能會致使內存泄漏,但對於 Client,可能有的時候會比較便利。

G. IoService getService():

這個方法返回與當前會話對象關聯的IoService 實例。 關於TCP鏈接的關閉: 不管在客戶端仍是服務端,IoSession 都用於表示底層的一個TCP 鏈接,那麼你會發現不管 是Server 端仍是Client 端的IoSession 調用close()方法以後,TCP 鏈接雖然顯示關閉, 但 主線程仍然在運行,也就是JVM 並未退出,這是由於IoSession 的close()僅僅是關閉了TCP 的鏈接通道,並無關閉Server 端、Client 端的程序。你須要調用IoService 的dispose() 方法中止Server 端、Client 端。


###(5.)IoSessionConfig: 這個方法用於指定這次會話的配置,它有以下經常使用的方法:

A. void setReadBufferSize(int size):

這個方法設置讀取緩衝的字節數,但通常不須要調用這個方法,由於IoProcessor 會自動調 整緩衝的大小。你能夠調用setMinReadBufferSize()、setMaxReadBufferSize()方法,這 樣不管IoProcessor 不管如何自動調整,都會在你指定的區間。

B. void setIdleTime(IdleStatus status,int idleTime):

這個方法設置關聯在通道上的讀、寫或者是讀寫事件在指定時間內未發生,該通道就進入空 閒狀態。一旦調用這個方法,則每隔idleTime 都會回調過濾器、IoHandler 中的sessionIdle() 方法。

C. void setWriteTimeout(int time):

這個方法設置寫操做的超時時間。

D. void setUseReadOperation(boolean useReadOperation):

這個方法設置IoSession 的read()方法是否可用,默認是false。


(6.)IoHandler:

這個接口是你編寫業務邏輯的地方,從上面的示例代碼能夠看出,讀取數據、發送數據基本 都在這個接口總完成,這個實例是綁定到IoService 上的,有且只有一個實例(沒有給一個 IoService 注入一個IoHandler 實例會拋出異常)。它有以下幾個方法:

A. void sessionCreated(IoSession session):

這個方法當一個Session 對象被建立的時候被調用。對於TCP 鏈接來講,鏈接被接受的時候 調用,但要注意此時TCP 鏈接並未創建,此方法僅表明字面含義,也就是鏈接的對象 IoSession 被建立完畢的時候,回調這個方法。 對於UDP 來講,當有數據包收到的時候回調這個方法,由於UDP 是無鏈接的。

B. void sessionOpened(IoSession session):

這個方法在鏈接被打開時調用,它老是在sessionCreated()方法以後被調用。對於TCP 來 說,它是在鏈接被創建以後調用,你能夠在這裏執行一些認證操做、發送數據等。 對於UDP 來講,這個方法與sessionCreated()沒什麼區別,可是緊跟其後執行。若是你每 隔一段時間,發送一些數據,那麼sessionCreated()方法只會在第一次調用,可是 sessionOpened()方法每次都會調用。

C. void sessionClosed(IoSession session) :

對於TCP 來講,鏈接被關閉時,調用這個方法。 對於UDP 來講,IoSession 的close()方法被調用時纔會毀掉這個方法。

D. void sessionIdle(IoSession session, IdleStatus status) :

這個方法在IoSession 的通道進入空閒狀態時調用,對於UDP 協議來講,這個方法始終不會 被調用。

E. void exceptionCaught(IoSession session, Throwable cause) :

這個方法在你的程序、Mina 自身出現異常時回調,通常這裏是關閉IoSession。

F. void messageReceived(IoSession session, Object message) :

接收到消息時調用的方法,也就是用於接收消息的方法,通常狀況下,message 是一個 IoBuffer 類,若是你使用了協議編解碼器,那麼能夠強制轉換爲你須要的類型。一般咱們 都是會使用協議編解碼器的, 就像上面的例子, 由於協議編解碼器是 TextLineCodecFactory,因此咱們能夠強制轉message 爲String 類型。

G. void messageSent(IoSession session, Object message) :

當發送消息成功時調用這個方法,注意這裏的措辭,發送成功以後,也就是說發送消息是不 能用這個方法的。 發送消息的時機: 發送消息應該在sessionOpened()、messageReceived()方法中調用IoSession.write()方法 完成。由於在sessionOpened()方法中,TCP 鏈接已經真正打開,一樣的在messageReceived() 方法TCP 鏈接也是打開狀態,只不過二者的時機不一樣。sessionOpened()方法是在TCP 鏈接 創建以後,接收到數據以前發送;messageReceived()方法是在接收到數據以後發送,你可 以完成依據收到的內容是什麼樣子,決定發送什麼樣的數據。 由於這個接口中的方法太多,所以一般使用適配器模式的IoHandlerAdapter,覆蓋你所感 興趣的方法便可。


(7.)IoBuffer:

這個接口是對JAVA NIO 的ByteBuffer 的封裝,這主要是由於ByteBuffer 只提供了對基本 數據類型的讀寫操做,沒有提供對字符串等對象類型的讀寫方法,使用起來更爲方便,另外, ByteBuffer 是定長的,若是想要可變,將很麻煩。IoBuffer 的可變長度的實現相似於 StringBuffer。IoBuffer 與ByteBuffer 同樣,都是非線程安全的。本節的一些內容若是不 清楚,能夠參考java.nio.ByteBuffer 接口。 這個接口有以下經常使用的方法:

A. static IoBuffer allocate(int capacity,boolean useDirectBuffer):

這個方法內部經過SimpleBufferAllocator 建立一個實例,第一個參數指定初始化容量,第 二個參數指定使用直接緩衝區仍是JAVA 內存堆的緩存區,默認爲false。

B. void free():

釋放緩衝區,以便被一些IoBufferAllocator 的實現重用,通常沒有必要調用這個方法,除 非你想提高性能(但可能未必效果明顯)。

C. IoBuffer setAutoExpand(boolean autoExpand):

這個方法設置IoBuffer 爲自動擴展容量,也就是前面所說的長度可變,那麼能夠看出長度 可變這個特性默認是不開啓的。

D. IoBuffer setAutoShrink(boolean autoShrink):

這個方法設置IoBuffer 爲自動收縮,這樣在compact()方法調用以後,能夠裁減掉一些沒 有使用的空間。若是這個方法沒有被調用或者設置爲false,你也能夠經過調用shrink() 方法手動收縮空間。

E. IoBuffer order(ByteOrder bo):

這個方法設置是Big Endian 仍是Little Endian,JAVA 中默認是Big Endian,C++和其餘 語言通常是Little Endian。

F. IoBuffer asReadOnlyBuffer():

這個方法設置IoBuffer 爲只讀的。

G. Boolean prefixedDataAvailable(int prefixLength,int maxDataLength):

這個方法用於數據的最開始的一、二、4 個字節表示的是數據的長度的狀況,prefixLentgh 表示這段數據的前幾個字節(只能是一、二、4 的其中一個)的表明的是這段數據的長度, maxDataLength 表示最多要讀取的字節數。返回結果依賴於等式 remaining()-prefixLength>=maxDataLength,也就是總的數據-表示長度的字節,剩下的字 節數要比打算讀取的字節數大或者相等。

H. String getPrefixedString(int prefixLength,CharsetDecoder decoder):

若是上面的方法返回true,那麼這個方法將開始讀取表示長度的字節以後的數據,注意要 保持這兩個方法的prefixLength 的值是同樣的。 G、H 兩個方法在後面講到的PrefixedStringDecoder 中的內部實現使用。 IoBuffer 剩餘的方法與ByteBuffer 都是差很少的,額外增長了一些便利的操做方法,例如: IoBuffer putString(String value,CharsetEncoder encoder)能夠方便的以指定的編碼方 式存儲字符串、InputStream asInputStream()方法從IoBuffer 剩餘的未讀的數據中轉爲 輸入流等。


###(8.)IoFuture: 在Mina 的不少操做中,你會看到返回值是XXXFuture,實際上他們都是IoFuture 的子類, 看到這樣的返回值,這個方法就說明是異步執行的,主要的子類有ConnectFuture、 CloseFuture 、ReadFuture 、WriteFuture 。這個接口的大部分操做都和 java.util.concurrent.Future 接口是相似的,譬如:await()、awaitUninterruptibly() 等,通常咱們經常使用awaitUninterruptibly()方法能夠等待異步執行的結果返回。 這個接口有以下經常使用的方法: ####A. IoFuture addListener(IoFutureListener<?> listener): 這個方法用於添加一個監聽器, 在異步執行的結果返回時監聽器中的回調方法 operationComplete(IoFuture future),也就是說,這是替代awaitUninterruptibly()方 法另外一種等待異步執行結果的方法,它的好處是不會產生阻塞。 ####B. IoFuture removeListener(IoFutureListener<?> listener): 這個方法用於移除指定的監聽器。 ####C. IoSession getSession(): 這個方法返回當前的IoSession。 舉個例子,咱們在客戶端調用connect()方法訪問Server 端的時候,實際上這就是一個異 步執行的方法,也就是調用connect()方法以後當即返回,執行下面的代碼,而不論是否連 接成功。那麼若是我想在鏈接成功以後執行一些事情(譬如:獲取鏈接成功後的IoSession 對象),該怎麼辦呢?按照上面的說明,你有以下兩種辦法: 第一種:

ConnectFuture future = connector.connect(new InetSocketAddress(
HOSTNAME, PORT));
// 等待是否鏈接成功,至關因而轉異步執行爲同步執行。
future.awaitUninterruptibly();
// 鏈接成功後獲取會話對象。若是沒有上面的等待,因爲connect()方法是異步的,session可能會沒法獲取。
session = future.getSession();

第二種:

ConnectFuture future = connector.connect(new InetSocketAddress(
HOSTNAME, PORT));
future.addListener(new IoFutureListener<ConnectFuture>() {
@Override
public void operationComplete(ConnectFuture future) {
try {
	Thread.sleep(5000);
} catch (InterruptedException e) {
	e.printStackTrace();
}
IoSession session = future.getSession();
System.out.println("++++++++++++++++++++++++++++");
}
});
System.out.println("*************");

爲了更好的看清楚使用監聽器是異步的,而不是像awaitUninterruptibly()那樣會阻塞主 線程的執行,咱們在回調方法中暫停5 秒鐘,而後輸出+++,在最後輸出***。咱們執行代碼 以後,你會發現首先輸出***(這證實了監聽器是異步執行的),而後IoSession 對象Created, 系統暫停5 秒,而後輸出+++,最後IoSession 對象Opened,也就是TCP 鏈接創建。


##4.日誌配置: 前面的示例代碼中提到了使用SLF4J 做爲日誌門面,這是由於Mina 內部使用的就是SLF4J, 你也使用SLF4J 能夠與之保持一致性。 Mina 若是想啓用日誌跟蹤Mina 的運行細節,你能夠配置LoggingFilter 過濾器,這樣你可 以看到Session 創建、打開、空閒等一系列細節在日誌中輸出,默認SJF4J 是按照DEBUG 級別輸出跟蹤信息的,若是你想給某一類別的Mina 運行信息輸出指定日誌輸出級別,能夠 調用LoggingFilter 的setXXXLogLevel(LogLevel.XXX)。 例:

LoggingFilter lf = new LoggingFilter();
lf.setSessionOpenedLogLevel(LogLevel.ERROR);
acceptor.getFilterChain().addLast("logger", lf);

這裏IoSession 被打開的跟蹤信息將以ERROR 級別輸出到日誌。


##5.過濾器: 前面咱們看到了LoggingFilter、ProtocolCodecFilter 兩個過濾器,一個負責日誌輸出, 一個負責數據的編解碼,經過最前面的Mina 執行流程圖,在IoProcessor 與IoHandler 之 間能夠有不少的過濾器,這種設計方式爲你提供可插拔似的擴展功能提供了很是便利的方 式,目前的Apache CXF、Apache Struts2 中的攔截器也都是同樣的設計思路。 Mina 中的IoFilter 是單例的,這與CXF、Apache Struts2 沒什麼區別。 IoService 實例上會綁定一個DefaultIoFilterChainBuilder 實例, DefaultIoFilterChainBuilder 會把使用內部的EntryImpl 類把全部的過濾器按照順序連在 一塊兒,組成一個過濾器鏈。 DefaultIoFilterChainBuilder 類以下經常使用的方法: ####A. void addFirst(String name,IoFilter filter): 這個方法把過濾器添加到過濾器鏈的頭部,頭部就是IoProcessor 以後的第一個過濾器。同 樣的addLast()方法把過濾器添加到過濾器鏈的尾部。 ####B. void addBefore(String baseName,String name,IoFilter filter): 這個方法將過濾器添加到baseName 指定的過濾器的前面,一樣的addAfter()方法把過濾器 添加到baseName 指定的過濾器的後面。這裏要注意不管是那種添加方法,每一個過濾器的名 字(參數name)必須是惟一的。 ####C. IoFilter remove(Stirng name): 這個方法移除指定名稱的過濾器,你也能夠調用另外一個重載的remove()方法,指定要移除 的IoFilter 的類型。 ####D. 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()要求相同。

相關文章
相關標籤/搜索