本文使用mina-2.0.16.jar
Apache Mina Server 是一個網(wǎng)絡(luò)通信應(yīng)用框架,也就是說钢坦,它主要是對基于TCP/IP倔监、UDP/IP協(xié)議棧的通信框架(當(dāng)然戒幔,也可以提供JAVA 對象的序列化服務(wù)访递、虛擬機(jī)管道通信服務(wù)等)粒梦,Mina 可以幫助我們快速開發(fā)高性能亮航、高擴(kuò)展性的網(wǎng)絡(luò)通信應(yīng)用,Mina 提供了事件驅(qū)動匀们、異步(Mina 的異步IO 默認(rèn)使用的是JAVA NIO 作為底層支持)操作的編程模型缴淋。
Mina 同時提供了網(wǎng)絡(luò)通信的Server 端、Client 端的封裝泄朴,無論是哪端重抖,Mina 在整個網(wǎng)通通信結(jié)構(gòu)中都處于如下的位置:可見Mina 的API 將真正的網(wǎng)絡(luò)通信與我們的應(yīng)用程序隔離開來,你只需要關(guān)心你要發(fā)送祖灰、接收的數(shù)據(jù)以及你的業(yè)務(wù)邏輯即可钟沛。同樣的,無論是哪端局扶,Mina 的執(zhí)行流程如下所示:
(1) IoService:這個接口在一個線程上負(fù)責(zé)套接字的建立恨统,擁有自己的Selector,監(jiān)聽是否有連接被建立三妈。
(2) IoProcessor:這個接口在另一個線程上畜埋,負(fù)責(zé)檢查是否有數(shù)據(jù)在通道上讀寫,也就是說它也擁有自己的Selector畴蒲,這是與我們使用Java NIO 編碼時的一個不同之處由捎,通常在JavaNIO 編碼中,我們都是使用一個Selector饿凛,也就是不區(qū)分IoService與IoProcessor 兩個功能接口狞玛。另外,IoProcessor 負(fù)責(zé)調(diào)用注冊在IoService 上的過濾器涧窒,并在過濾器鏈之后調(diào)用IoHandler心肪。
(3) IoFilter:這個接口定義一組攔截器,這些攔截器可以包括日志輸出纠吴、黑名單過濾硬鞍、數(shù)據(jù)的編碼(write 方向)與解碼(read 方向)等功能,其中數(shù)據(jù)的encode 與decode是最為重要的戴已、也是你在使用Mina 時最主要關(guān)注的地方固该。
(4) IoHandler:這個接口負(fù)責(zé)編寫業(yè)務(wù)邏輯,也就是接收糖儡、發(fā)送數(shù)據(jù)的地方伐坏。
- 服務(wù)器端
/**
* mina服務(wù)器端
* @author mazaiting
*/
public class MinaServer {
/**
* 監(jiān)聽的端口
*/
private static final int PORT = 9123;
public static void start() throws IOException{
// 1. 創(chuàng)建IoAcceptor
IoAcceptor acceptor = new NioSocketAcceptor();
// 2. 加入日志記錄過濾器,用SL4J庫記錄信息
acceptor.getFilterChain().addLast("logger", new LoggingFilter());
// 3. 加入編碼過濾器握联,用于解碼所有收到的信息,使用 new TextLineCodecFactory() r
// 發(fā)送的信息進(jìn)行編碼桦沉,返回是MINA自帶的,功能有限金闽,只能處理文本戒者String類型纯露。
acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(
new TextLineCodecFactory(Charset.forName("UTF-8"))));
// 4. 設(shè)置ServerHandler, 自定義的Handler,TimeServerHandler
acceptor.setHandler(new TimerServerHandler());
// 5. 設(shè)置Session的對應(yīng)I/O processor讀緩存區(qū)大小2048,通常這個參數(shù)不需要設(shè)置
acceptor.getSessionConfig().setReadBufferSize(2048);
// 6. 設(shè)置空閑時間代芜, 這里的BOTH_IDLE指EADER_IDLE和WRITER_IDLE都為10秒
acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10);
// 7. 綁定監(jiān)聽端口9123.
// acceptor.bind(new InetSocketAddress("localhost",PORT));
acceptor.bind(new InetSocketAddress(PORT));
}
public static void main(String[] args) throws IOException {
start();
}
/**
* 服務(wù)器端消息處理器
* @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 {
/**
* 對接收到的消息(已經(jīng)解碼)迕行下一步處理挤庇,這里對收到的字符串進(jìn)行判斷钞速,
* 如果是”quit”則斷開連接;否則輸出當(dāng)前時間的字符串格式罚随;
*/
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 {
/**
* 當(dāng)Session處于IDLE狀態(tài)的時候玉工,輸出空閑狀態(tài)次數(shù);
*/
System.out.println("IDLE:" + session.getIdleCount(status));
}
}
}
運(yùn)行代碼淘菩,在cmd(命令提示符) 中輸入"telnet 127.0.0.1 9123"遵班,連接成功后隨意輸入字符,并按下回車潮改,即可看到當(dāng)前時間狭郑。
- 客戶端
/**
* mina客戶端
* @author mazaiting
*/
public class MinaClient {
/**
* 監(jiān)聽的端口
*/
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());
}
}
}