本文使用mina-2.0.16.jar
Apache Mina Server 是一個網絡通信應用框架,也就是說,它主要是對基于TCP/IP、UDP/IP協議棧的通信框架(當然,也可以提供JAVA 對象的序列化服務、虛擬機管道通信服務等),Mina 可以幫助我們快速開發高性能、高擴展性的網絡通信應用,Mina 提供了事件驅動、異步(Mina 的異步IO 默認使用的是JAVA NIO 作為底層支持)操作的編程模型。
Mina 同時提供了網絡通信的Server 端、Client 端的封裝,無論是哪端,Mina 在整個網通通信結構中都處于如下的位置:可見Mina 的API 將真正的網絡通信與我們的應用程序隔離開來,你只需要關心你要發送、接收的數據以及你的業務邏輯即可。同樣的,無論是哪端,Mina 的執行流程如下所示:
(1) IoService:這個接口在一個線程上負責套接字的建立,擁有自己的Selector,監聽是否有連接被建立。
(2) IoProcessor:這個接口在另一個線程上,負責檢查是否有數據在通道上讀寫,也就是說它也擁有自己的Selector,這是與我們使用Java NIO 編碼時的一個不同之處,通常在JavaNIO 編碼中,我們都是使用一個Selector,也就是不區分IoService與IoProcessor 兩個功能接口。另外,IoProcessor 負責調用注冊在IoService 上的過濾器,并在過濾器鏈之后調用IoHandler。
(3) IoFilter:這個接口定義一組攔截器,這些攔截器可以包括日志輸出、黑名單過濾、數據的編碼(write 方向)與解碼(read 方向)等功能,其中數據的encode 與decode是最為重要的、也是你在使用Mina 時最主要關注的地方。
(4) IoHandler:這個接口負責編寫業務邏輯,也就是接收、發送數據的地方。
- 服務器端
/**
* mina服務器端
* @author mazaiting
*/
public class MinaServer {
/**
* 監聽的端口
*/
private static final int PORT = 9123;
public static void start() throws IOException{
// 1. 創建IoAcceptor
IoAcceptor acceptor = new NioSocketAcceptor();
// 2. 加入日志記錄過濾器,用SL4J庫記錄信息
acceptor.getFilterChain().addLast("logger", new LoggingFilter());
// 3. 加入編碼過濾器,用于解碼所有收到的信息,使用 new TextLineCodecFactory() r
// 發送的信息進行編碼,返回是MINA自帶的,功能有限,只能處理文本戒者String類型。
acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(
new TextLineCodecFactory(Charset.forName("UTF-8"))));
// 4. 設置ServerHandler, 自定義的Handler,TimeServerHandler
acceptor.setHandler(new TimerServerHandler());
// 5. 設置Session的對應I/O processor讀緩存區大小2048,通常這個參數不需要設置
acceptor.getSessionConfig().setReadBufferSize(2048);
// 6. 設置空閑時間, 這里的BOTH_IDLE指EADER_IDLE和WRITER_IDLE都為10秒
acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10);
// 7. 綁定監聽端口9123.
// acceptor.bind(new InetSocketAddress("localhost",PORT));
acceptor.bind(new InetSocketAddress(PORT));
}
public static void main(String[] args) throws IOException {
start();
}
/**
* 服務器端消息處理器
* @author mazaiting
*/
public static class TimerServerHandler extends IoHandlerAdapter{
@Override
public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
/**
* 自定義異常處理, 要不然異常會被“吃掉”;
*/
cause.printStackTrace();
}
@Override
public void messageReceived(IoSession session, Object message) throws Exception {
/**
* 對接收到的消息(已經解碼)迕行下一步處理,這里對收到的字符串進行判斷,
* 如果是”quit”則斷開連接;否則輸出當前時間的字符串格式;
*/
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 {
/**
* 當Session處于IDLE狀態的時候,輸出空閑狀態次數;
*/
System.out.println("IDLE:" + session.getIdleCount(status));
}
}
}
運行代碼,在cmd(命令提示符) 中輸入"telnet 127.0.0.1 9123",連接成功后隨意輸入字符,并按下回車,即可看到當前時間。
- 客戶端
/**
* mina客戶端
* @author mazaiting
*/
public class MinaClient {
/**
* 監聽的端口
*/
private static final int PORT = 9123;
public static void start() {
IoConnector connector = new NioSocketConnector();
connector.setConnectTimeoutMillis(30000);
connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(
new TextLineCodecFactory(Charset.forName("UTF-8"),
LineDelimiter.WINDOWS.getValue(),
LineDelimiter.WINDOWS.getValue())));
connector.setHandler(new ClientHandler("你好!\r\n 大家好!"));
connector.connect(new InetSocketAddress("localhost", 9123));
}
public static void main(String[] args) {
start();
}
private static class ClientHandler extends IoHandlerAdapter{
private String values;
public ClientHandler(String values) {
this.values = values;
}
@Override
public void sessionOpened(IoSession session) throws Exception {
session.write(values);
}
@Override
public void messageReceived(IoSession session, Object message) throws Exception {
System.out.println(message.toString());
}
}
}