MINA服務端的應用應用體系結構
基本上,服務器監聽端口傳入請求,處理它們并發送回復。它還為每個客戶端創建和處理會話(無論我們是基于TCP或者UDP的時候)。
- IOAcceptor在網絡上監聽傳入的連接/數據包
- 對于新鏈接,將會創建一個新的會話,并在該會話中處理來自IP地址/端口組合的所有后續請求
- 為會話接收的所有數據包將按照圖中所示的方式遍歷過濾器。過濾器可用于修改數據包的內容(如轉換為對象,添加/刪除信息等)。PacketEncoder/Decoder對于將原始字節轉換為高級對象,非常有用。
- 最后數據包或者轉換成對象的數據將加載到IOHandler中,IOHandler可以非常完美的處理業務需求。
示例TCP服務器
接下來將引導您完成構建基于MINA的程序的過程,逐步構建一個時間服務器。開發服務器端需要以下幾個先決條件:
1.MINA 2.x Core
2.JDK1.5或者更高
3.SLF4J1.3.0或者更高(注1中的下載文件中已經包含了對應的包)
- Log4J 1.2 的用戶需要的包:slf4j-api.jar,slf4j-log4j12.jar,和Log4J 1.2.x
- Log4J 1.3的用戶需要的包:slf4j-api.jar,slf4j-log4j13.jar,和Log4J 1.3.x
- java.util.logging的用戶需要的包:slf4j-api.jar和slf4j-jdk14.jar,
- 注:請確保你使用了正確的slf4j-*.jar匹配你的日志框架。
實際上, slf4j-log4j12.jar 和log4j-1.3.x.jar 不能一起使用,并且會發生故障。
開始服務器端代碼
首先創建java project項目,和普通的創建方式一致,創建libs文件夾將需要的包復制進去:
接下來創建對應的服務類:
package com.fmblzf.minaservice;
/**
*
* @Copy:2017-fmblzf
* @ProjectName:MINA_SERVER
* @ClassDecription:
* @ClassName:com.fmblzf.minaservice.MinaServerMain
* @Creator:zhaofeng
* @CreatTime:2017年5月27日 上午11:50:55
* @FixPerson:fmblzf
* @FixTime:2017年5月27日 上午11:50:55
* @Tag:
* @version V1.0
*
*/
public class MinaServerMain {
//設置端口號
private static final int PORT = 9321;
public static void main(String[] args) {
}
}
首先,我們需要一個將用于偵聽傳入連接的對象。由于該程序將基于TCP/IP,我們將在我們的程序中添加一個SocketAcceptor,我們創建對應的NioSocketAcceptor對象,并且將其綁定到PORT端口上。
IoAcceptor ioAcceptor = new NioSocketAcceptor();
ioAcceptor.bind(new InetSocketAddress(PORT));
接下來設置過濾器,配置Session,以及設置處理對象
public static void main(String[] args) throws IOException {
//首先,添加對應的網絡監聽對象,等待處理連接和回復消息
IoAcceptor ioAcceptor = new NioSocketAcceptor();
//添加過濾器
ioAcceptor.getFilterChain().addLast("logger",new LoggingFilter());//設置日志管理過濾器
ioAcceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(new ObjectSerializationCodecFactory()));//設置字節處理過濾器
//添加IOHandler
ioAcceptor.setHandler(new MainServerHandler());
//添加Session配置
ioAcceptor.getSessionConfig().setReadBufferSize(2048);//設置讀緩存區的大小
ioAcceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10);//設置讀寫的空閑時間都是10秒
ioAcceptor.bind(new InetSocketAddress(PORT));
}
創建自定義的IoHandler對象
/**
* 邏輯處理類
* @Copy:2017-fmblzf
* @ProjectName:MINA_SERVER
*
* @ClassDecription:
* @ClassName:com.fmblzf.minaservice.MainServerHandler
* @Creator:fmblzf
* @CreatTime:2017年5月27日 下午12:41:08
* @FixPerson:fmblzf
* @FixTime:2017年5月27日 下午12:41:08
* @Tag:
* @version V1.0
*
*/
private static class MainServerHandler extends IoHandlerAdapter{
/**
* 接收到消息
* @see org.apache.mina.core.service.IoHandlerAdapter#messageReceived(org.apache.mina.core.session.IoSession, java.lang.Object)
*
*/
@Override
public void messageReceived(IoSession session, Object message)
throws Exception {
String str = message.toString();
if( str.trim().equalsIgnoreCase("quit") ) {
session.closeNow();
return;
}
Date date = new Date();
session.write( date.toString() );
System.out.println("Message written...");
}
@Override
public void sessionIdle(IoSession session, IdleStatus status)
throws Exception {
System.out.println( "IDLE " + session.getIdleCount( status ));
}
/**
* 發送消息給客戶端
* @see org.apache.mina.core.service.IoHandlerAdapter#messageSent(org.apache.mina.core.session.IoSession, java.lang.Object)
*
*/
@Override
public void messageSent(IoSession session, Object message)
throws Exception {
}
@Override
public void sessionCreated(IoSession session) throws Exception {
}
@Override
public void sessionOpened(IoSession session) throws Exception {
}
@Override
public void sessionClosed(IoSession session) throws Exception {
}
}
示例UDP服務器
因為MINA的統一API接口,所以UDP和TCP在結構上是一致的,只有IoAcceptor對應的實現類是不一致,所以接下來我們看一看UDP創建的核心代碼:
/**
* 創建UDP連接
* @Title: createUdp
* @Description: TODO
* @throws IOException
*
*/
private static void createUdp() throws IOException {
IoAcceptor ioAcceptor = new NioDatagramAcceptor();
// 添加過濾器
ioAcceptor.getFilterChain().addLast("logger", new LoggingFilter());// 設置日志管理過濾器
ioAcceptor.getFilterChain().addLast("codec",
new ProtocolCodecFilter(new ObjectSerializationCodecFactory()));// 設置字節處理過濾器
// 添加IOHandler
ioAcceptor.setHandler(new MainServerHandler());
// 添加Session配置
ioAcceptor.getSessionConfig().setReadBufferSize(2048);// 設置讀緩存區的大小
ioAcceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10);// 設置讀寫的空閑時間都是10秒
ioAcceptor.bind(new InetSocketAddress(PORT+1));
}
從代碼我們可以看見,UDP的IoAcceptor的實現類是NioDatagramAcceptor,其他的結構編寫都是一致。
至此我們的TCP/UDP的核心代碼已經完成,至于其他的衍生部分,感興趣的朋友可以參考官網來接著學習。