Apache Mina Server 是一個網絡通信應用框架,也就是說,它主要是對基於TCP/IP、UDP/IP協議棧的通信框架(當然,也可以提供JAVA 對象的序列化服務、虛擬機管道通信服務等),Mina 可以幫助我們快速開發高性能、高擴展性的網絡通信應用,Mina 提供了事件驅動、異步(Mina 的異步IO 默認使用的是JAVA NIO 作為底層支持)操作的編程模型。Mina 主要有1.x 和2.x 兩個分支,這里我們講解最新版本2.0,如果你使用的是Mina 1.x,那么可能會有一些功能並不適用。學習本文檔,需要你已掌握JAVA IO、JAVA NIO、JAVASocket、JAVA 線程及並發庫(java.util.concurrent.*)的知識。Mina 同時提供了網絡通信的Server 端、Client 端的封裝,無論是哪端,Mina 在整個網通通信結構中都處於如下的位置:可見Mina 的API 將真正的網絡通信與我們的應用程序隔離開來,你只需要關心你要發送、接收的數據以及你的業務邏輯即可。同樣的,無論是哪端,Mina 的執行流程如下所示:
(1.) IoService:這個接口在一個線程上負責套接字的建立,擁有自己的Selector,監聽是否有連接被建立。
(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 內部的自動識別機制。