apache-Mina學習筆記
阿新 • • 發佈:2019-02-07
Apache Mina
mina是apache基於socket nio的一套框架。支援基於socket
NIO庫的TCP/UDP應用程式的開發。
看原始碼發現,它底層使用了執行緒池的技術。即Mina本身實現了執行緒池,為了提高效率,可以通過自己寫連線池來使用Mina。這麼理解,連線池中有多個IoSession,對於每一個IoSession,Mina不會為一個IoSession起一個執行緒,而是利用執行緒池來處理,這是NIO的好處。
Mina TCP的幾個重要介面:
這裡簡單的介紹一下mina的框架:
- IoSession :是對底層連線的封裝,對應於當前客戶端到伺服器端的一個TCP連線例項。連線池中儲存著多個IoSession。
- IoHandler :這個介面負責編寫業務邏輯,也就是接收、傳送資料的地方。這也是實際開發過程中需要使用者自己編寫的部分程式碼。我們的專案中searchHub DataSource繼承了該介面。
- IoService:這個介面是網路的入口,IoAcceptor和IoConnector都實現這個介面。
- IoFilter:過濾器。他是用來過濾訊息的。從IoService(網路介面)出來的資料或者進入IoService(網路介面)的資料都會經過IoFilter的處理。最重要的就是日誌和解碼和編碼。
- IoHandler:處理器。它是連結應用和IoFilter的橋樑,是進行業務處理的,從IoFilter出來的資料會發到IoHandler中處理。
目錄結構:
1.服務端程式:(服務端繫結3005埠)
package com.dvn.li.main;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import org.apache.log4j.Logger;
import org.apache.mina.common.IdleStatus;
import org.apache.mina.common.IoAcceptor;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.textline.LineDelimiter;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
import com.dvn.li.handler.Demo1ServerHandler;
public class Demo1Server {
private static Logger logger = Logger.getLogger(Demo1Server.class);
private static int PORT = 3005;
public static void main(String[] args) {
IoAcceptor acceptor = null; // 建立連線
try {
// 建立一個非阻塞的server端的Socket
acceptor = new NioSocketAcceptor();
// 設定過濾器(使用Mina提供的文字換行符編解碼器)
acceptor.getFilterChain().addLast(
// 新增訊息過濾器
"codec",
new ProtocolCodecFilter(new TextLineCodecFactory(Charset
.forName("UTF-8"),
LineDelimiter.WINDOWS.getValue(),
LineDelimiter.WINDOWS.getValue())));
// 設定讀取資料的緩衝區大小
acceptor.getSessionConfig().setReadBufferSize(2048);
// 讀寫通道10秒內無操作進入空閒狀態
acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10);
// 繫結邏輯處理器
acceptor.setHandler(new Demo1ServerHandler()); // 新增業務處理
// 繫結埠
acceptor.bind(new InetSocketAddress(PORT));
logger.info("服務端啟動成功... 埠號為:" + PORT);
} catch (Exception e) {
logger.error("服務端啟動異常....", e);
e.printStackTrace();
}
}
}
伺服器端的業務邏輯處理器是Demo1ServerHandler---看它的具體實現:
package com.dvn.li.handler;
import java.util.Date;
import org.apache.log4j.Logger;
import org.apache.mina.common.IdleStatus;
import org.apache.mina.common.IoHandlerAdapter;
import org.apache.mina.common.IoSession;
public class Demo1ServerHandler extends IoHandlerAdapter {
public static Logger logger = Logger.getLogger(Demo1ServerHandler.class);
@Override
public void sessionCreated(IoSession session) throws Exception {
logger.info("服務端與客戶端建立連線...");
}
@Override
public void sessionOpened(IoSession session) throws Exception {
logger.info("服務端與客戶端連線開啟...");
}
@Override
public void messageReceived(IoSession session, Object message)
throws Exception {
String msg = message.toString();
logger.info("服務端接收到的資料為:" + msg);
if ("bye".equals(msg)) { // 服務端斷開連線的條件
session.close();
}
Date date = new Date();
String sendMess = "";
//邏輯處理
if(msg.contains("Hello")){
sendMess = "mina收到你的Hello!";
}else{
sendMess = "請跟mina say Hello!";
}
session.write(sendMess+" "+date); //往客戶端傳送訊息
}
@Override
public void messageSent(IoSession session, Object message) throws Exception {
session.close();
logger.info("服務端傳送資訊成功...");
}
@Override
public void sessionClosed(IoSession session) throws Exception {
}
@Override
public void sessionIdle(IoSession session, IdleStatus status)
throws Exception {
logger.info("服務端進入空閒狀態...");
}
@Override
public void exceptionCaught(IoSession session, Throwable cause)
throws Exception {
logger.error("服務端傳送異常...", cause);
}
}
2.客戶端程式
package com.dvn.li.main;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import org.apache.log4j.Logger;
import org.apache.mina.common.ConnectFuture;
import org.apache.mina.common.IoConnector;
import org.apache.mina.common.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.textline.LineDelimiter;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
import org.apache.mina.transport.socket.nio.NioSocketConnector;
import com.dvn.li.handler.Demo1ClientHandler;
public class MinaClient01 {
private static Logger logger = Logger.getLogger(MinaClient01.class);
private static String HOST = "127.0.0.1";
private static int PORT = 3005;
public static void main(String[] args) {
// 建立一個非阻塞的客戶端程式
IoConnector connector = new NioSocketConnector();
// 設定連結超時時間
connector.setConnectTimeout(30000);
// 新增過濾器
connector.getFilterChain().addLast(
"codec",
new ProtocolCodecFilter(new TextLineCodecFactory(Charset
.forName("UTF-8"), LineDelimiter.WINDOWS.getValue(),
LineDelimiter.WINDOWS.getValue())));
// 新增業務邏輯處理器類
connector.setHandler(new Demo1ClientHandler());
IoSession session = null;
try {
ConnectFuture future = connector.connect(new InetSocketAddress(HOST, PORT));// 建立連線
future.awaitUninterruptibly();// 等待連線建立完成
session = future.getSession();// 獲得session(可以結合連線池,從連線池獲取一個session)
session.write("你好, mina");// 往服務端傳送訊息
} catch (Exception e) {
logger.error("客戶端連結異常...", e);
}
session.getCloseFuture().awaitUninterruptibly();// 等待連線斷開
connector.dispose();
}
}
和服務端程式碼極其相似,不同的是服務端是建立NioSocketAcceptor物件,而客戶端是建立NioSocketConnector物件;同樣需要新增編碼解碼過濾器和業務邏輯過濾器;
業務邏輯過濾器程式碼:
package com.dvn.li.handler;
import org.apache.log4j.Logger;
import org.apache.mina.common.IoHandlerAdapter;
import org.apache.mina.common.IoSession;
public class Demo1ClientHandler extends IoHandlerAdapter {
private static Logger logger = Logger.getLogger(Demo1ClientHandler.class);
@Override
public void messageReceived(IoSession session, Object message)
throws Exception {
String msg = message.toString();
logger.info("客戶端接收到的資訊為:" + msg);
}
@Override
public void exceptionCaught(IoSession session, Throwable cause)
throws Exception {
logger.error("客戶端發生異常...", cause);
}
}
3.執行過程:
a. 啟動服務端Demo1Server ,然後再啟動客戶端MinaClient01(客戶端傳送的訊息是“Hello,mina”)
b. 服務端接收訊息並處理:如果客戶端傳送的訊息包含hello,將 "mina收到你的Hello! "返回給客戶端, 否則返回 "請跟mina say Hello!"
4.執行結果