Apache MINA(Multipurpose Infrastructure for Network Applications) 是 Apache 組織一個為開發高性能和高可用性的網絡應用程序提供了非常便利的框架。
當前發行的 MINA 版本支持基於 Java NIO 技術的 TCP/UDP 應用程序開發、串口通訊程序(只在最新的預覽版中提供),MINA 所支持的功能也在進一步的擴展中。
最近要去一家游戲面試,一朋友建議看一下mina和netty,他們公司以及好些合作公司游戲開發中都用到過,所以開始爬資料學習mina,做個有備無患.嘿嘿,mina作為一個開發高性能和高可用性的網絡應用程序的框架,當然它不單於游戲開發中,其它高性能高可用性網絡應用也會用到,希望對后來接觸的同學有幫助.
資金線混有兩個技術框架是一定要懂得如何使用的,它們就是MINA和HTTPCLIENT(沒聽過的,就先百度一下) 。支付寶和銀行前置機之間的通訊基本都是使用者兩種框架,即使你不懂SOCKET戒者HTTP很底層的協議也沒多大關系 。 對於HTTPCLIENT有過很多實踐了,從我剛迕支付寶的第一個項目個人誠信通,到最近的建行境外收單直連改造,都是使用HTTP通訊 。
跟MINA類似的框架,迓有著名的Jboss Netty,代碼框架非常類似,使用方法也大同小異,可以說Jboss Netty是MINA的改良版
from支付寶 -藍秋鵬(仲景)
環境准備
1.首先到官方網站下載最新的 MINA 版本,地址是:http://www.apache.org/dyn/closer.cgi/mina/mina/2.0.7/dist/apache-mina-2.0.7-bin.zip
2.下載 MINA 的依賴包 slf4j。下載地址 http://www.slf4j.org/download.html
MINA 使用此項目作為日志信息的輸出,而MINA 本身並不附帶此項目包,slf4j 項目解壓后有很多的文件,本例中只需要其中的slf4j-api-1.7.2.jar 和 slf4j-simple-1.7.2.jar 這兩個 jar 文件。如果沒有這兩個文件就會導致啟動例子程序的時候報 org/slf4j/LoggerFactory 類沒找到的錯誤。
MINA 基本類的描述
在介紹架構之前先認識幾個接口:
IoAccepter 相當於網絡應用程序中的服務器端
IoConnector 相當於客戶端
IoSession 當前客戶端到服務器端的一個連接實例
IoHandler 業務處理邏輯
IoFilter 過濾器用於懸接通訊層接口與業務層接口
MINA 的架構圖
在圖中的模塊鏈中,IoService 便是應用程序的入口,IoAccepter 是 IoService 的一個擴展接口。IoService 接口可以用來添加多個 IoFilter,這些 IoFilter 符合責任鏈模式並由 IoProcessor 線程負責調用。而 IoAccepter 在 ioService 接口的基礎上還提供綁定某個通訊端口以及取消綁定的接口。
當客戶首次訪問采用MINA編寫的程序時,IoAcceptor作為線程運行,負責接受來自客戶的請求。當有客戶請求連接時,創建一個 Session,該Session與IoProcessor、SocketChannel以及IOService聯系起來。IoProcessor也作為另外一個線程運行,定時檢查客戶是否有數據到來,並對客戶請求進行處理,依次調用在IOService注冊的各個IoFilter,最后調用 IoHandler進行最終的邏輯處理,再將處理后的結果Filter后返回給客戶端。
一個 IoHandler 接口中具有如下一些方法
void exceptionCaught(IoSession session, Throwable cause)
當接口中其他方法拋出異常未被捕獲時觸發此方法
void messageReceived(IoSession session, Object message)
當接收到客戶端的請求信息后觸發此方法.
void messageSent(IoSession session, Object message)
當信息已經傳送給客戶端后觸發此方法.
void sessionClosed(IoSession session)
當連接被關閉時觸發,例如客戶端程序意外退出等等.
void sessionCreated(IoSession session)
當一個新客戶端連接后觸發此方法.
void sessionIdle(IoSession session, IdleStatus status)
當連接空閑時觸發此方法.
void sessionOpened(IoSession session)
當連接后打開時觸發此方法,一般此方法與 sessionCreated 會被同時觸發
前面我們提到 IoService 是負責底層通訊接入,而 IoHandler 是負責業務處理的。那么 MINA 架構圖中的 IoFilter 作何用途呢?答案是你想作何用途都可以。但是有一個用途卻是必須的,那就是作為 IoService 和 IoHandler 之間的橋梁。IoHandler 接口中最重要的一個方法是 messageReceived,這個方法的第二個參數是一個 Object 型的消息,總所周知,Object 是所有 Java 對象的基礎,那到底誰來決定這個消息到底是什么類型呢?答案也就在這個 IoFilter 中。在前面使用的例子中,我們添加了一個 IoFilter 是 new ProtocolCodecFilter(new TextLineCodecFactory()),這個過濾器的作用是將來自客戶端輸入的信息轉換成一行行的文本后傳遞給 IoHandler,因此我們可以在 messageReceived 中直接將 msg 對象強制轉換成 String 對象。
而如果我們不提供任何過濾器的話,那么在 messageReceived 方法中的第二個參數類型就是一個 byte 的緩沖區,對應的類是 org.apache.mina.common.ByteBuffer。雖然你也可以將解析客戶端信息放在 IoHandler 中來做,但這並不是推薦的做法,使原來清晰的模型又模糊起來,變得 IoHandler 不只是業務處理,還得充當協議解析的任務。
Mina中自帶的一些主要過濾器說明
BlacklistFilter 設置一些IP 地址為黑名單,不允許訪問。
BufferedWriteFilter 設置輸出時像BufferedOutputStream 一樣進行緩沖。
CompressionFilter 設置在輸入、輸出流時啟用JZlib 壓縮。
ConnectionThrottleFilter 這個過濾器指定同一個IP 地址(不含端口號)上的請求在多長的毫秒值內可以有一個請求,如果小於指定的時間間隔就有連續兩個請求,那么第二個請求將被忽略(IoSession.close())。正如Throttle 的名字一樣,調節訪問的頻率。這個過濾器最好放在過濾器鏈的前面。
FileRegionWriteFilter 如果你想使用File 對象進行輸出,請使用這個過濾器。要注意,你需要使用WriteFuture 或者在messageSent() 方法中關閉File 所關聯的FileChannel 通道。
StreamWriteFilter 如果你想使用InputStream 對象進行輸出,請使用這個過濾器。要注意,你需要使用WriteFuture 或者在messageSent()方法中關閉File 所關聯的FileChannel 通道。
NoopFilter 這個過濾器什么也不做,如果你想測試過濾器鏈是否起作用,可以用它來測試。
ProfilerTimerFilter 這個過濾器用於檢測每個事件方法執行的時間, 所以最好放在過濾器鏈的前面。
ProxyFilter 這個過濾器在客戶端使用ProxyConnector 作為實現時,會自動加入到過濾器鏈中,用於完成代理功能。
SessionAttributeInitializingFilter 這個過濾器在IoSession 中放入一些屬性(Map),通常放在過濾器的前面,用於放置一些初始化的信息。
MdcInjectionFilter 針對日志輸出做MDC 操作,可以參考LOG4J 的MDC、NDC 的文檔。
WriteRequestFilter CompressionFilter、RequestResponseFilter 的基類,用於包裝寫請求的過濾器。
還有一些過濾器,這里沒有列出,譬如:前面的LoggingFilger 日志過濾器。
實例代碼模擬
服務端演示
服務端業務處理
package org.dennisit.mina.demo; import org.apache.mina.core.service.IoHandlerAdapter; import org.apache.mina.core.session.IoSession; /** * * HelloHandler 負責業務邏輯處理 * * 功 能: TODO * 類 名: HelloHandler.java * * ver 変更日 角色 擔當者 変更內容 * ────────────────────────────────────────────── * V1.00 2013-2-21 模塊 蘇若年 初版 * * Copyright (c) 2013 dennisit corporation All Rights Reserved. * * Email:<a href="mailto:DennisIT@163.com">發送郵件</a> * */
public class ServerHandler extends IoHandlerAdapter{ /** * 有新連接時觸發 */ @Override public void sessionOpened(IoSession session) throws Exception { System.out.println("服務端, session open for " + session.getRemoteAddress()); } /** * 連接關閉時觸發 */ @Override public void sessionClosed(IoSession session) throws Exception { System.out.println("服務端, session closed from " + session.getRemoteAddress()); } /** * 收到來自客戶端的消息 */ @Override public void messageReceived(IoSession session, Object message) throws Exception { String clientIP = session.getRemoteAddress().toString(); System.out.println("服務端接收到來自IP:"+clientIP+"的消息:"+message ); } /** * 當有異常發生時觸發 */ @Override public void exceptionCaught(IoSession session, Throwable cause) throws Exception { System.out.println("服務端,發生異常" + cause.getMessage()); session.close(); } }
服務端主類
package org.dennisit.mina.demo; import java.io.IOException; import java.net.InetSocketAddress; import org.apache.mina.core.service.IoAcceptor; import org.apache.mina.core.session.IdleStatus; import org.apache.mina.filter.codec.ProtocolCodecFilter; import org.apache.mina.filter.codec.textline.TextLineCodecFactory; import org.apache.mina.filter.logging.LoggingFilter; import org.apache.mina.transport.socket.nio.NioSocketAcceptor; /** * * MinaServer * * 功 能: TODO * 類 名: MinaServer.java * * ver 変更日 角色 擔當者 変更內容 * ────────────────────────────────────────────── * V1.00 2013-2-21 模塊 蘇若年 初版 * * Copyright (c) 2013 dennisit corporation All Rights Reserved. * * Email:<a href="mailto:DennisIT@163.com">發送郵件</a> * */
public class MinaServer { private static final int PORT = 8888; public static void main(String[] args) throws IOException { // 構造接收器
IoAcceptor acceptor = new NioSocketAcceptor(); ServerHandler handler = new ServerHandler(); acceptor.setHandler(handler); // 讀寫通道10秒內無操作進入空閑狀態
acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10); //添加過濾器和日志組件
acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(new TextLineCodecFactory())); acceptor.getFilterChain().addLast("logging", new LoggingFilter()); // 啟動服務
acceptor.bind(new InetSocketAddress(PORT)); System.out.println("MinaServer started on port " + PORT); } }
main方法中定義了整型的端口8888,在實際應用中一般通過antx.properties配置端口,返樣就可以把配置的權限交給運維部門。
每一個信息都會通過在IoAcceptor中定義的過濾器鏈的所有過濾器,完成個性化的日志記錄和解碼工作。日志過濾器用SL4J庫記錄信息,而編碼過濾器則解碼所有收到的信息.
啟動后提示:MinaServer started on port 8888表示啟動成功,如果啟動失敗,問題無外乎是類沒找到或者端口占用。如果端口被占用的話,換一個,修改 PORT 常量值后再次編譯並啟動。
測試服務器
打開命令行窗口,輸入 telnet localhost 8080 后,發送信息后回車再去看看剛啟動的服務程序有何反應。我的反應如下:
表示mina開發的網絡程序服務端經成功運行 .
win7下遇到telnet不是內部或外部命令的問題解決
依次點擊“開始--->控制面板--->卸載或更改程序--->打開或關閉Windows功能
勾選Telnet服務器和Telnet客戶端並確定即可.
然后在windows服務中啟動
安裝后默認是上面的情況,根據自己的需求設置成啟動或者手動啟動,筆者改為手動啟動.然后啟動telnet服務.
客戶端演示:
我們使用telnet作為客戶端發包給服務器,現在使用Mina框架編寫一個簡單的客戶端
客戶端業務處理類
package org.dennisit.mina.demo; import java.util.Date; import org.apache.mina.core.service.IoHandlerAdapter; import org.apache.mina.core.session.IoSession; /** * * ClientHandler.java * * 功 能: TODO * 類 名: ClientHandler.java * * ver 変更日 角色 擔當者 変更內容 * ────────────────────────────────────────────── * V1.00 2013-2-21 模塊 蘇若年 初版 * * Copyright (c) 2013 dennisit corporation All Rights Reserved. * * Email:<a href="mailto:DennisIT@163.com">發送郵件</a> * */
public class ClientHandler extends IoHandlerAdapter{ /** * 在會話打開時向服務端發送當前日期 */ @Override public void sessionOpened(IoSession session) throws Exception { session.write("客戶端會話打開時間" +new Date()); } @Override public void messageReceived(IoSession session, Object message) throws Exception { System.out.println("我是客戶端,收到響應:" + message.toString()); } @Override public void messageSent(IoSession session, Object message) throws Exception { System.out.println("我是客戶端,我發送的消息:" + message); } @Override public void sessionClosed(IoSession session) throws Exception { System.out.println("客戶端會話關閉時間"+new Date()); } @Override public void exceptionCaught(IoSession session, Throwable cause) throws Exception { System.out.println("我是客戶端,系統出現異常:" + cause.getMessage()); session.close(); } }
客戶端主類
package org.dennisit.mina.demo; import java.net.InetSocketAddress; import org.apache.mina.core.filterchain.IoFilter; import org.apache.mina.core.future.ConnectFuture; import org.apache.mina.core.service.IoConnector; import org.apache.mina.core.session.IoSession; import org.apache.mina.filter.codec.ProtocolCodecFilter; import org.apache.mina.filter.codec.textline.TextLineCodecFactory; import org.apache.mina.filter.logging.LoggingFilter; import org.apache.mina.transport.socket.nio.NioSocketConnector; /** * * MinaClient.java * * 功 能: TODO * 類 名: MinaClient.java * * ver 変更日 角色 擔當者 変更內容 * ────────────────────────────────────────────── * V1.00 2013-2-21 模塊 蘇若年 初版 * * Copyright (c) 2013 dennisit corporation All Rights Reserved. * * Email:<a href="mailto:DennisIT@163.com">發送郵件</a> * */
public class MinaClient { private static final String HOST = "127.0.0.1"; private static final int PORT = 8888; public static void main(String[] args) { IoConnector connector = new NioSocketConnector(); connector.setHandler(new ClientHandler()); // 設置連接超時時間 單位毫秒
connector.setConnectTimeout(30000); //添加過濾器和日志組件
IoFilter filter = new ProtocolCodecFilter(new TextLineCodecFactory()); connector.getFilterChain().addLast(" codec", filter); connector.getFilterChain().addLast("logging", new LoggingFilter()); // 創建連接
IoSession session = null; try { ConnectFuture connect = connector.connect(new InetSocketAddress(HOST, PORT)); // 等待連接創建完成
connect.awaitUninterruptibly(); // 獲取session
session = connect.getSession(); session.write("客戶端連接測試"); } catch (Exception e) { System.out.println("客戶端連接異常"); } session.getCloseFuture().awaitUninterruptibly(); connector.dispose(); } }
運行效果
可以發現客戶端和服務器的代碼非常類似,客戶端演示的是直接發送String消息,可以使用MINA自帶的編碼協議,客戶端處理器和服務端處理器是很像的,它們都是在收到數據包之后的處理。
客戶端業務處理類中比服務端處理器新增一個接口messageSent(…),在實際應用中我們經常需要記錄我們發送的日志,方便后期問題追蹤。日志的記錄需要有唯一性的標記,最好的辦法就是把報文的標記在發送之前保存在IoSession,使用session.getAttribute("KEY")取出標記。
在項目開發的實際應用中,我們的通訊報文一般都不會使用String傳輸,因為系統的運行環境或者編程語言一般都是不同的,最常用的就是以字節傳輸,報文的格式需要雙方約定規范,比如xml格式,或者定長格式或者其它格式,最終都會轉換成字節傳輸。那么這里就需要我們編寫自定義的編碼和解碼方案。
編寫編碼方案工廠類,注冊自定義的編碼方案
在Mina 中的協議編解碼器通過過濾器 ProtocolCodecFilter 構造,這個過濾器的構造方法需 要一個 ProtocolCodecFactory,這從前面注冊 TextLineCodecFactory 的代碼就可以看出來。
ProtocolCodecFactory 中有如下兩個方法:
public interface ProtocolCodecFactory {
ProtocolEncoder getEncoder(IoSession session) throws Exception;
ProtocolDecoder getDecoder(IoSession session) throws Exception;
}
因此,構建一個 ProtocolCodecFactory 需要 ProtocolEncoder、ProtocolDecoder 兩個實例。你可能要問 JAVA 對象和二進制數據之間如何轉換呢?這個要依據具體的通信協議,也就是 Server 端要和 Client 端約定網絡傳輸的數據是什么樣的格式,譬如:第一個字節表示數據 長度,第二個字節是數據類型,后面的就是真正的數據(有可能是文字、有可能是圖片等等), 然后你可以依據長度從第三個字節向后讀,直到讀取到指定第一個字節指定長度的數據。
簡單的說,HTTP 協議就是一種瀏覽器與 Web 服務器之間約定好的通信協議,雙方按照指定 的協議編解碼數據。我們再直觀一點兒說,前面一直使用的 TextLine 編解碼器就是在讀取 網絡上傳遞過來的數據時,只要發現哪個字節里存放的是 ASCII 的 10、13 字符(\r、\n), 就認為之前的字節就是一個字符串(默認使用 UTF-8 編碼)。
以上所說的就是各種協議實際上就是網絡七層結構中的應用層協議,它位於網絡層(IP)、 傳輸層(TCP)之上,Mina 的協議編解碼器就是讓你實現一套自己的應用層協議棧。
編碼器實現
package org.dennisit.mina.codec; import java.nio.charset.Charset; import java.nio.charset.CharsetEncoder; import org.apache.mina.core.buffer.IoBuffer; import org.apache.mina.core.session.IoSession; import org.apache.mina.filter.codec.ProtocolEncoderAdapter; import org.apache.mina.filter.codec.ProtocolEncoderOutput; /** * * HEncoder.java * * 功 能: 編碼器 * 類 名: HEncoder.java * * ver 変更日 角色 擔當者 変更內容 * ────────────────────────────────────────────── * V1.00 2013-2-21 模塊 蘇若年 初版 * * Copyright (c) 2013 dennisit corporation All Rights Reserved. * * Email:<a href="mailto:DennisIT@163.com">發送郵件</a> * */
public class HEncoder extends ProtocolEncoderAdapter { private final Charset charset; /** * 構造依賴 * @param charset */
public HEncoder(Charset charset){ this.charset = charset; } /** * 編碼規則 */ @Override public void encode(IoSession session, Object obj, ProtocolEncoderOutput out) throws Exception { CharsetEncoder encoder = charset.newEncoder(); IoBuffer io = IoBuffer.allocate(100).setAutoExpand(true); io.putString(obj.toString(), encoder); io.put((byte)'\r'); io.put((byte)'\n'); io.flip(); out.write(io); } }
在 Mina 中編寫編碼器可以實現 ProtocolEncoder,其中有 encode()、dispose()兩個方法需 要實現。這里的 dispose()方法用於在銷毀編碼器時釋放關聯的資源,由於這個方法一般我 們並不關心,所以通常我們直接繼承適配器 ProtocolEncoderAdapter。
解碼器實現
package org.dennisit.mina.codec; import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.nio.charset.CharsetEncoder; import org.apache.mina.core.buffer.IoBuffer; import org.apache.mina.core.session.IoSession; import org.apache.mina.filter.codec.CumulativeProtocolDecoder; import org.apache.mina.filter.codec.ProtocolDecoderOutput; /** * * HDecoder.java * * 功 能: 解碼器 * 類 名: HDecoder.java * * ver 変更日 角色 擔當者 変更內容 * ────────────────────────────────────────────── * V1.00 2013-2-21 模塊 蘇若年 初版 * * Copyright (c) 2013 dennisit corporation All Rights Reserved. * * Email:<a href="mailto:DennisIT@163.com">發送郵件</a> * */
public class HDecoder extends CumulativeProtocolDecoder{ private final Charset charset; /** * 構造依賴 * @param charset */
public HDecoder(Charset charset) { this.charset = charset; } @Override protected boolean doDecode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception { CharsetDecoder decoder = charset.newDecoder(); //設置數據存放的IoBuffer大小
IoBuffer ioBuffer = IoBuffer.allocate(1024).setAutoExpand(true); System.out.println("開始解碼"); while(in.hasRemaining()){ byte bte = in.get(); //將數據存放到IoBuffer中
ioBuffer.put(bte); if(bte == '\n'){ ioBuffer.flip(); byte[] bt = new byte[ioBuffer.limit()]; ioBuffer.get(bt); String message = new String (bt,decoder.charset()); //重置ioBuffer
ioBuffer = IoBuffer.allocate(100).setAutoExpand(true); out.write(message); } } return true; } }
在 Mina 中編寫解碼器,可以實現 ProtocolDecoder 接口,其中有 decode()、finishDecode()、 dispose()三個方法。這里的 finishDecode()方法可以用於處理在 IoSession 關閉時剩余的 讀取數據,一般這個方法並不會被使用到,除非協議中未定義任何標識數據什么時候截止 的約定,譬如:Http 響應的 Content-Length 未設定,那么在你認為讀取完數據后,關閉 TCP 連接(IoSession 的關閉)后,就可以調用這個方法處理剩余的數據,當然你也可以忽略調 剩余的數據。同樣的,一般情況下,我們只需要繼承適配器 ProtocolDecoderAdapter,關 注 decode()方法即可。
但前面說過解碼器相對編碼器來說,最麻煩的是數據發送過來的規模,以聊天室為例,一個 TCP 連接建立之后,那么隔一段時間就會有聊天內容發送過來,也就是 decode()方法會被往 復調用,這樣處理起來就會非常麻煩。那么 Mina 中幸好提供了 CumulativeProtocolDecoder 類,從名字上可以看出累積性的協議解碼器,也就是說只要有數據發送過來,這個類就會去 讀取數據,然后累積到內部的 IoBuffer 緩沖區,但是具體的拆包(把累積到緩沖區的數據 解碼為 JAVA 對象)交由子類的 doDecode()方法完成,實際上 CumulativeProtocolDecoder 就是在 decode()反復的調用暴漏給子類實現的 doDecode()方法。
具體執行過程如下所示:
A. 你的 doDecode()方法返回 true 時,CumulativeProtocolDecoder 的 decode()方法會首先判斷你是否在 doDecode()方法中從內部的 IoBuffer 緩沖區讀取了數據,如果沒有,ce); buffer.putString(smsContent, ce);buffer.flip();則會拋出非法的狀態異常,也就是你的 doDecode()方法返回 true 就表示你已經消費了 本次數據(相當於聊天室中一個完整的消息已經讀取完畢),進一步說,也就是此時你 必須已經消費過內部的 IoBuffer 緩沖區的數據(哪怕是消費了一個字節的數據)。如果 驗證過通過,那么 CumulativeProtocolDecoder 會檢查緩沖區內是否還有數據未讀取, 如果有就繼續調用 doDecode()方法,沒有就停止對 doDecode()方法的調用,直到有新 的數據被緩沖。
B. 當你的 doDecode()方法返回 false 時,CumulativeProtocolDecoder 會停止對 doDecode() 方法的調用,但此時如果本次數據還有未讀取完的,就將含有剩余數據的 IoBuffer 緩 沖區保存到 IoSession 中,以便下一次數據到來時可以從 IoSession 中提取合並。如果 發現本次數據全都讀取完畢,則清空 IoBuffer 緩沖區。簡而言之,當你認為讀取到的數據已經夠解碼了,那么就返回 true,否則就返回 false。這 個 CumulativeProtocolDecoder 其實最重要的工作就是幫你完成了數據的累積,因為這個工 作是很煩瑣的。
創建編解碼工廠
package org.dennisit.mina.codec; import java.nio.charset.Charset; import org.apache.mina.core.session.IoSession; import org.apache.mina.filter.codec.ProtocolCodecFactory; import org.apache.mina.filter.codec.ProtocolDecoder; import org.apache.mina.filter.codec.ProtocolEncoder; /** * * HCoderFactory.java * * 功 能: 編解碼工廠 * 類 名: HCoderFactory.java * * ver 変更日 角色 擔當者 変更內容 * ────────────────────────────────────────────── * V1.00 2013-2-21 模塊 蘇若年 初版 * * Copyright (c) 2013 dennisit corporation All Rights Reserved. * * Email:<a href="mailto:DennisIT@163.com">發送郵件</a> * */
public class HCoderFactory implements ProtocolCodecFactory { private final HEncoder encoder; private final HDecoder decoder; public HCoderFactory() { this(Charset.defaultCharset()); } public HCoderFactory(Charset charSet) { this.encoder = new HEncoder(charSet); this.decoder = new HDecoder(charSet); } @Override public ProtocolDecoder getDecoder(IoSession session) throws Exception { return decoder; } @Override public ProtocolEncoder getEncoder(IoSession session) throws Exception { return encoder; } }
這個工廠類就是包裝了編碼器、解碼器,通過接口中的 getEncoder()、getDecoder() 方法向 ProtocolCodecFilter 過濾器返回編解碼器實例,以便在過濾器中對數據進行編解碼 處理。
我們創建好了自定義的編解碼有關的類后,我們設置Server和Client的編碼工廠為我們自定義的編碼工廠類:
//使用mina中自帶的編解碼協議
acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(new TextLineCodecFactory())); //使用自定義的編解碼協議
DefaultIoFilterChainBuilder chain = acceptor.getFilterChain(); chain.addLast("mycoder", new ProtocolCodecFilter(new HCoderFactory(Charset.forName("UTF-8"))));
參考文獻: http://blog.sina.com.cn/s/blog_48b9354d0100psts.html
參考文獻: http://xiaominghimi.blog.51cto.com/2614927/969791
參考文獻: http://qianhao-1987.iteye.com/blog/1476125
轉載請注明出處:[http://www.cnblogs.com/dennisit/archive/2013/02/21/2920693.html]