Mina框架技術知識介紹
一.MINA框架簡介
Apache MINA 是一個網絡應用框架,有助於用戶非常方便地開發高性能、高伸縮性的網絡應用。它通過Java NIO提供了一個抽象的、事件驅動的、異步的位於各種傳輸協議(如TCP/IP和UDP/IP)之上的API,Apache MINA 通常可被稱之爲NIO 框架庫、客戶端/服務器框架庫或者一個網絡socket庫。
MINA框架的特點有:基於java NIO類庫開發;採用非阻塞方式的異步傳輸;事件驅動;支持批量數據傳輸;支持TCP、UDP協議;控制反轉的設計模式(支持Spring);採用優雅的松耦合架構;可靈活的加載過濾器機制;單元測試更容易實現;可自定義線程的數量,以提高運行於多處理器上的性能;採用回調的方式完成調用,線程的使用更容易。
1.2 Mina的框架
當遠程客戶首次訪問採用MINA編寫的程序時,IoAcceptor作爲線程運行,負責接受來自客戶的請求。當有客戶請求連接時,創建一個IoSession,該IoSession與IoProcessor、SocketChannel以及IOService聯繫起來。IoProcessor也作爲另外一個線程運行,定時檢查客戶是否有數據到來,並對客戶請求進行處理,依次調用在IOService註冊的各個IoFilter,最後調用IoHandler進行最終的邏輯處理,再將處理後的結果Filter後返回給客戶端。
1.3 Mina的現有應用
MINA框架的應用比較廣泛,應用的開源項目有Apache Directory、AsyncWeb、ApacheQpid、QuickFIX/J、Openfire、SubEthaSTMP、red5等。MINA框架當前穩定版本是1.1.6,最新的2.0版本目前已經發布了M1版本。
二.MINA框架具體技術
2.1MINA框架的常用類
1.類NioSocketAcceptor
用於創建服務端監聽
2.類NioSocketConnector
用於創建客戶端連接;
3.類IoSession用來保存會話屬性和發送消息;可以理解爲服務器與客戶端的特定連接,該連接由服務器地址、端口以及客戶端地址、端口來決定。客戶端發起請求時,指定服務器地址和端口,客戶端也會指定或者根據網絡路由信息自動指定一個地址、自動分配一個端口。這個地址、端口對構成一個Session。
Session是服務器端對這種連接的抽象,MINA對其進行了封裝,定義了IoSession接口,用來代表客戶端與服務器的連接,在服務器端來指代客戶端,實現對客戶端的操作、綁定與客戶端有關的信息與對象。通過利用Session的這個概念,編寫程序時就可以在服務器端非常方便地區分出是當前處理的是哪個客戶端的請求、維持客戶端的狀態信息、可以實現客戶端之間相互通訊。
IoSession提供以下一些常用方法:
功能說明:設置/獲取用戶定義的屬性。將該屬性與session聯繫起來,方便以後處理用戶請求時使用。比如如果要求用戶登錄後才能繼續進行操作,那麼在用戶成功登陸後,可以通過setAttribute()設置一個屬性,當用戶以後繼續請求時,可以通過getAttribute()獲取該屬性來判斷用戶是否登錄。
2)getRemoteAddress()
功能說明:獲取遠程客戶端地址。
3)getId()
功能說明:獲取Session的Id4)getCreationTime()
功能說明:獲得創建時間
5)getLastIoTime()
功能說明:獲得上次IO時間
6) getConfig()
功能說明:獲得配置信息。
7)write(Object message)
功能說明:將數據發送給客戶端。
8)close()
功能說明:關閉Session。
(說明:可以在Session中發送數據,但是Session沒有提供讀取數據的方法,讀取數據通過另一套機制在IoHandler的messageReceived()中實現。)
4.類IoHandlerAdapter
用於定義業務邏輯,常用的方法有:
(1)void exceptionCaught(IoSession session, Throwable cause)
功能說明:有異常發生時被觸發。
(2)void messageReceived(IoSession session, Object message)
功能說明:有消息到達時被觸發,message代表接收到的消息。
(3)void messageSent(IoSession session, Object message)
功能說明:發送消息時時被觸發,即在調用IoSession.write()時被觸發,message代表將要發送的消息。
(4)void sessionClosed(IoSession session)
功能說明:當連接關閉時被觸發,即Session終止時被觸發。
(5)void sessionCreated(IoSession session)
功能說明:當創建一個新連接時被觸發,即當開始一個新的Session時被觸發。
(6)void sessionIdle(IoSession session, IdleStatus status)
功能說明:當連接空閒時被觸發。使用IoSessionConfig中的setIdleTime(IdleStatus status, int idleTime)方法可以設置session的空閒時間。如果該Session的空閒時間超過設置的值,該方法被觸發,可以通過session.getIdleCount(status)來獲取sessionIdle被觸發的次數。
(7)void sessionOpened(IoSession session)
功能說明:當打開一個連接時被觸發。在目前的實現中,好像 sessionOpened 和 sessionCreated 沒有太大區別,sessionCreated 在 sessionOpened 之前被觸發。
IoHandler是一個接口,一般情況沒有必要直接實現該接口的每一個方法。MINA提供了一個IoHandlerAdapter類,該類實現了IoHandler要求的方法,但是都沒有做任何處理。當我們要編寫自己的Handler時,可以擴展IoHandlerAdapter,重寫我們關心的事件方法即可。比如,一般情況,我們比較關心是否接收到數據這個時間,那麼我們就可以覆蓋messageReceived方法,不用管其他方法。
5.類IoFilter
IoFilter用來對客戶的請求或發送給客戶的數據進行filter。與IoHandler一樣,Filter也是基於事件的,通過實現IoFilter接口,就可以對通信過程中的Session的事件進行處理。
6.Event
MINA可以看成是事件驅動的。通常在網絡通訊中,可以將整個過程劃分爲幾個基本的階段,如建立連接、數據通信、關閉連接。 數據通信一般包括數據的發送和接收,由於在通信過程中,可能要多次發送和接收數據,以進行不同的業務交互。不可能一直都接收和發送數據,因此就有Idle出現,在MINA中,如果在設定的時間內沒有數據發送或接收,那麼就會觸發一個Idle事件。由於某種原因,可能會發生錯誤,導致系統異常發生,引發exception。因此,如果從事件發生的角度看的話,就可以在MINA中將通信看成由一個建立鏈接(sessionCreated 和 sessionOpened )、多個數據接收和發送、一個關閉連接事件以及多個Idle事件等7種事件組成的過程。
Session是對雙方相互通信的抽象,因此通信的過程就是一系列與Session相關的事件。
在MINA現在對TCP的實現中,sessionCreated 和 sessionOpened 沒有區別。因此嚴格來說,有6種類型的事件。
三、代碼事例
功能描述:編寫一個服務器監聽客戶機的程序,當客戶機訪問服務器的時候,服務器輸出客戶機的訪問信息(http),然後將訪問信息和第幾位客戶告訴客戶機。 處理器代碼:
SamplMinaServerHandler.java
import org.apache.mina.common.IoHandlerAdapter; import org.apache.mina.common.IoSession;
public class SamplMinaServerHandler extends IoHandlerAdapter {
//當一個客端端連結進入時
@Override
public void sessionOpened(IoSession session) throws Exception { System.out.println("incomming client : "+session.getRemoteAddress());
}
//當一個客戶端關閉時
@Override
public void sessionClosed(IoSession session) {
System.out.println("one Clinet Disconnect !");
}
//當客戶端發送的消息到達時:
@Override
public void messageReceived(IoSession session, Object message) throws Exception { //我們己設定了服務器解析消息的規則是一行一行讀取,這裏就可轉爲String:
String s=(String)message;
// Write the received data back to remote peer
System.out.println("收到客戶機發來的消息: "+s); //測試將消息回送給客戶斷 session.write(s+count); count++; }
private int count=0; }
package com.javake.mina.sampleserver;
import java.net.InetSocketAddress;
import org.apache.mina.common.DefaultIoFilterChainBuilder;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
import org.apache.mina.transport.socket.SocketAcceptor;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;public class MainServer {
public static void main(String[] args) throws Exception { //創建一個非阻塞的Server端Socket,用NIO
SocketAcceptor acceptor = new NioSocketAcceptor();
//創建接收數據的過濾器
DefaultIoFilterChainBuilder chain = acceptor.getFilterChain(); //設定這個過濾器將一行一行(/r/n)的讀取數據
chain.addLast("myChin", new ProtocolCodecFilter(new TextLineCodecFactory())); //設定服務器端的消息 處理器:一個SamplMinaServerHandler對象,
acceptor.setHandler(new SamplMinaServerHandler()); // 服務器端綁定的端口
int bindPort=9988;
//綁定端口,啓動服務器acceptor.bind(new InetSocketAddress(bindPort));