Mina簡介

Apache Mina Server 是一個網絡通信應用框架,也就是說,它主要是對基於TCP/IP、UDP/IP協議棧的通信框架(當然,也可以提供JAVA 對象的序列化服務、虛擬機管道通信服務等),Mina 可以幫助我們快速開發高性能、高擴展性的網絡通信應用,Mina 提供了事件驅動、異步(Mina 的異步IO 默認使用的是JAVA NIO 作爲底層支持)操作的編程模型。Mina 同時提供了網絡通信的Server 端、Client 端的封裝,Mina 的API 將真正的網絡通信與我們的應用程序隔離開來,你只需要關心你要發送、接收的數據以及你的業務邏輯即可。同樣的,無論是哪端,Mina 的執行流程如下所示:


(1.)  IoService:這個接口在一個線程上負責套接字的建立,擁有自己的Selector,監
聽是否有連接被建立。(Mina底層使用JAVA NIO, 因此它是典型的使用Reactor模式架構的,採用事件驅動編程 , Mina運行用戶自定義線程模型,可以是單線程、多線程、線程池等 ,跟JAVA Socket不一樣, Mina是非阻塞的Socket,它內部已經保證了對各個連接(session)的業務和數據的隔離,採用輪詢機制爲各個session分配CPU資源,所以,你就不需要再去考慮不同Socket連接需要用不同的線程去操縱的問題了。)

(2.)  IoProcessor:這個接口在另一個線程上負責檢查是否有數據在通道上讀寫,也就是說它也擁有自己的Selector,這是與我們使用JAVA NIO 編碼時的一個不同之處,通常在JAVA NIO 編碼中,我們都是使用一個Selector,也就是不區分IoService與 IoProcessor 兩個功能接口。另外,IoProcessor 負責調用註冊IoService 上的過濾器,並在過濾器鏈之後調用IoHandler。

(3.)  IoFilter:這個接口定義一組攔截器,這些攔截器可以包括日誌輸出、黑名單過濾、數據的編碼(write 方向)與解碼(read 方向)等功能,其中數據的encode 與 decode是最爲重要的、也是你在使用Mina 時最主要關注的地方。

(4.)  IoHandler:這個接口負責編寫業務邏輯,也就是接收、發送數據的地方。


 

1. 簡單的TCPServer:
(1.) 第一步:編寫IoService
  按照上面的執行流程,我們首先需要編寫IoService,IoService 本身既是服務端,又是客戶端,我們這裏編寫服務端,所以使用IoAcceptor 實現,由於IoAcceptor 是與協議無關的,因爲我們要編寫TCPServer,所以我們使用IoAcceptor 的實現NioSocketAcceptor,實際上底層就是調用java.nio.channels.ServerSocketChannel 類。當然,如果你使用了Apache 的APR 庫,那麼你可以選擇使AprSocketAcceptor 作爲TCPServer 的實現,據傳說Apache APR庫的性能比JVM 自帶的本地庫高出很多。那麼IoProcessor 是由指定的IoService 內部創建並調用的,我們並不需要關心。

這段代碼我們初始化了服務端的TCP/IP 的基於NIO 的套接字,然後調用IoSessionConfig設置讀取數據的緩衝區大小、讀寫通道均在10 秒內無任何操作就進入空閒狀態。

(2.) 第二步:編寫過濾器
這裏我們處理最簡單的字符串傳輸,Mina 已經爲我們提供了TextLineCodecFactory 編解碼器工廠來對字符串進行編解碼處理。

這段代碼要在acceptor.bind()方法之前執行,因爲綁定套接字之後就不能再做這些準備工作了。這裏先不用清楚編解碼器是如何工作的,這個是後面重點說明的內容,這裏你只需要清楚,我們傳輸的以換行符爲標識的數據,所以使用了Mina 自帶的換行符編解碼器工廠。

(3.) 第三步:編寫IoHandler

這裏我們只是簡單的打印Client 傳說過來的數據。

然後我們把這個IoHandler 註冊到IoService:

當然這段代碼也要在acceptor.bind()方法之前執行。然後我們運行MyServer 中的main 方法,你可以看到控制檯一直處於阻塞狀態,此時,我們用telnet 127.0.0.1 9123 訪問,然後輸入一些內容,當按下回車鍵,你會發現數據在Server 端被輸出,但要注意不要輸入中文,因爲Windows 的命令行窗口不會對傳輸的數據進行UTF-8 編碼。當輸入quit 結尾的字符串時,連接被斷開。這裏注意你如果使用的操作系統,或者使用的Telnet 軟件的換行符是什麼,如果不清楚,可以刪掉第二步中的兩個紅色的參數,使用TextLineCodec 內部的自動識別機制。



這邊的實例關於Filter可能只是用了系統的TextLineCodecFactory。其實這邊大多數情況是需要根據自己的場景編寫對應的編解碼實現的。具體書寫方式的話可以參考以下代碼:

 acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(
new MyTextLineCodecFactory()); //配置CodecFactory
這段是bind()方法中添加到filterchain中。


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;

public class MyTextLineCodecFactory implements ProtocolCodecFactory{

@Override
public ProtocolDecoder getDecoder(IoSession arg0) throws Exception {
// TODO Auto-generated method stub
return new MyTextLineDecoder();
}

@Override
public ProtocolEncoder getEncoder(IoSession arg0) throws Exception {
// TODO Auto-generated method stub
return new MyTextLineEncoder();
}

}
這是編解碼Factory


至於其中的兩個自定義的類書寫的話通過實現ProtocolDecoder接口和ProtocolEncoder接口。並填充具體的編解碼代碼。






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