1.為什麼要用Apache Mina框架
ApacheMina Server 是一個網絡通信應用框架,Mina 可以幫助我們快速開發高性能、高擴展性的網絡通信應用,Mina 提供了事件驅動、異步(Mina 的異步IO 默認使用的是JAVANIO 作為底層支持)操作的編程模型。
2.ApacheMina框架使用
Mina的執行流程:
> IoService:這個接口在一個線程上負責套接字的建立,擁有自己的Selector,監聽是否有連接被建立。
> IoProcessor:這個接口在另一個線程上,負責檢查是否有數據在通道上讀寫,也就是說它也擁有自己的Selector,這是與我們使用JAVA NIO 編碼時的一個不同之處,通常在JAVA NIO 編碼中,我們都是使用一個Selector,也就是不區分IoService與IoProcessor 兩個功能接口。另外,IoProcessor 負責調用注冊在IoService 上的過濾器,並在過濾器鏈之後調用IoHandler。
>IoFilter:這個接口定義一組攔截器,這些攔截器可以包括日志輸出、黑名單過濾、數據的編碼(write方向)與解碼(read 方向)等功能,其中數據的encode 與decode是最為重要的、也是你在使用Mina 時最主要關注的地方。
>IoHandler:這個接口負責編寫業務邏輯,也就是接收、發送數據的地方。
3.ApacheMina框架實例
該實例是WIFI雲管理平台的實際運用,主要實現通過和WIFI保持長連接管理WIFI,貼出部分代碼:
>服務器端UDPDispatcher.java
public class UDPDispatcher extendsHttpServlet implements ServletContextListener{
private static final int PORT =20000;
/** 30秒後超時 */
private static final int IDELTIMEOUT =30;
private static final longserialVersionUID = -4384594559203991221L;
@Override
public voidcontextInitialized(ServletContextEvent sce) {
NioDatagramAcceptor acceptor = newNioDatagramAcceptor();// 創建一個UDP的接收器
acceptor.setHandler(newUDPHandler());// 設置接收器的處理程序
Executor threadPool = newOrderedThreadPoolExecutor(100);// 建立線程池
acceptor.getFilterChain().addLast("exector",newExecutorFilter(threadPool));
acceptor.getFilterChain().addLast("logger",new LoggingFilter());
/*******心跳請求設置 begin*********/
KeepAliveMessageFactoryheartBeatFactory = new KeepAliveMessageFactoryImpl();
KeepAliveFilter heartBeat = newKeepAliveFilter(heartBeatFactory,
IdleStatus.BOTH_IDLE,KeepAliveRequestTimeoutHandler.CLOSE);
//設置是否forward到下一個filter
heartBeat.setRequestTimeoutHandler(newKeepAliveRequestTimeoutHandlerImpl());
heartBeat.setForwardEvent(true);
//設置心跳頻率
heartBeat.setRequestInterval(20);
heartBeat.setRequestTimeout(60);
acceptor.getFilterChain().addLast("heartbeat",heartBeat);
/*******心跳請求設置 end *********/
DatagramSessionConfig dcfg =acceptor.getSessionConfig();// 建立連接的配置文件
dcfg.setReadBufferSize(4096);// 設置接收最大字節默認2048
dcfg.setReceiveBufferSize(1024);//設置輸入緩沖區的大小
dcfg.setSendBufferSize(1024);// 設置輸出緩沖區的大小
dcfg.setReuseAddress(true);// 設置每一個非主監聽連接的端口可以重用
dcfg.setIdleTime(IdleStatus.BOTH_IDLE,IDELTIMEOUT);
try {
// 綁定端口
acceptor.bind(newInetSocketAddress(UDPConfigUtil.getHost(),PORT));
} catch (IOException e) {
// TODO Auto-generatedcatch block
e.printStackTrace();
}
}
@Override
public voidcontextDestroyed(ServletContextEvent sce) {
// TODO Auto-generated method stub
}
}
>心跳機制處理KeepAliveMessageFactoryImpl.java
public void messageSent(IoSessionsession, Object message) throws Exception {
}
@Override
public void exceptionCaught(IoSessionsession, Throwable cause)
throws Exception {
logger.error(cause);
session.close(true);
}
@Override
public voidmessageReceived(IoSessionsession, Object message) throws Exception {
logger.info("messageReceived");
if (message instanceof IoBuffer) {
IoBuffer buffer = (IoBuffer)message;
UDPRequestServer controller =UDPRequestServer.getInstance();
IoBuffer buffer1 =controller.dealRequest(buffer);
session.write(buffer1);
}
}
}
>業務邏輯處理UDPHandler.java
publicclass UDPHandler extends IoHandlerAdapter {
private final Logger logger =Logger.getLogger(this.getClass());
@Override
public void messageSent(IoSessionsession, Object message) throws Exception {
}
@Override
public void exceptionCaught(IoSessionsession, Throwable cause)
throws Exception {
logger.error(cause);
session.close(true);
}
@Override
public void messageReceived(IoSessionsession, Object message) throws Exception {
logger.info("messageReceived");
if (message instanceof IoBuffer) {
IoBuffer buffer = (IoBuffer) message;
UDPRequestServer controller = UDPRequestServer.getInstance();
IoBuffer buffer1 =controller.dealRequest(buffer);
session.write(buffer1);
}
}
}
注意點:
>心跳機制:
(1)客戶端會定時發送心跳請求(注意定時時間必須小於,服務器端的IDLE監控時間),同時需要監聽心跳反饋,以此來判斷是否與服務器丟失連接。對於服務器的心跳請求不給與反饋。
(2)心跳情況在60秒之內
(3)客戶端和服務端同時都需要設置心跳請求
Apache Mina開發手冊 http://www.linuxidc.com/Linux/2014-09/107137.htm
Apache Mina 白名單實現方法 http://www.linuxidc.com/Linux/2012-08/68992.htm
Apache MINA實戰 http://www.linuxidc.com/Linux/2012-04/59337.htm