Apache MINA(Multipurpose Infrastructure for Network Applications) 是 Apache 組織一個較新的項目,它為開發高性能和高可用性的網絡應用程序提供了非常便利的框架。當前發行的 MINA 版本支持基於 Java NIO 技術的 TCP/UDP 應用程序開發、串口通訊程序(只在最新的預覽版中提供),MINA 所支持的功能也在進一步的擴展中。 ——搜狗百科
序言
Mina是Java的一個網絡框架,它能幫你處理和隱藏許多網絡模塊的處理,對許多功能的使用,如filter,Handler,連接等進行了封裝,方便程序員的使用,關於Mina框架的詳細學習,請自行閱讀官網教程。
Mina的配置
要使用Mina框架,首先要導入幾個Jar包:
- mina-core-2.0.7.jar
 - mina-example-2.0.7.jar
 - slf4j-api-1.6.6.jar
 - slf4j-log4j12-1.6.6.jar
 - log4j-1.2.17.jar
 
slf4j-log4j12.jar and log4j-1.3.x.jar can not be used together, and will malfunction. ——來自官網-配置Mina
如官網所說,導入jar包的版本是需要注意的,比如slf4j-log4j12.jar不能和log4j-1.3.x.jar一起使用,會導致崩潰(゚Д゚≡)
技術基礎
在了解Mina框架之前,首先要對一些網絡的基本概念進行一些了解。
NIO與BIO
- NIO(non-blocking IO) :非阻塞式IO,對網絡的讀寫采用非阻塞式,可進行並發處理。
 - BIO(Blocking IO): 阻塞式IO, 對網絡的讀寫采用阻塞式,在完成讀寫操作前將完全無法操作。
 
在此,我們主要討論Mina的NIO(非阻塞式IO),在NIO的使用中,IO操作不阻塞程序的運行,所以你只要設置好IO操作的回調函數便可,當讀操作發生時,Mina會自動調用你編寫的回調函數,進行處理;寫操作也是同樣,只要調用IOSession.write(myContent),Mina便會是異步進行處理。當然這些處理都是Mina幫你封裝好的,使用者不需要過多的了解。如何建立NIO連接會在后面慢慢細說。
TCP與UDP
Mina支持對TCP和UDP的使用:
- TCP (Transmission Control Protocol) :傳輸控制協議,在進行服務器與客戶端的通信時,會對數據傳輸進行校驗,防止因網絡問題導致的丟包與亂序問題。
 - UDP (User Data Protocol) :用戶數據報協議,在服務器與客戶端的通信過程中,不對數據的有效性進行校驗,即發送端不在乎接收端是否接收到正確有序的數據。
 
TCP協議無非是在UDP上面加了一層數據校驗嘛╮(╯▽╰)╭,TCP協議額相較於UDP協議,在帶寬的占用量上多了一些,但卻省去了程序員處理數據包丟失,亂序的不少功夫;當然,選擇哪個協議進行制作,要根據項目的需求進行區分,大多數時候我們用的是TCP協議,但在一些不太在乎數據有效性的需求上,如實時通話,可以使用UDP協議來減少帶寬的消耗。
Mina的連接
我們先來做一個簡單的Mina連接,(代碼來自開源項目《迷你微信》服務器)
public class ServerNetwork {
	priv}ate InetSocketAddress inetSocketAddress;
	private IoAcceptor acceptor;
	
	public void init() {
		// 自己寫的,負責處理網絡層回調的類
		MinaServerHandle minaServerHandle = new MinaServerHandle
		// 建立一個NIO(非阻塞)的連接
		acceptor = new NioSocketAcceptor();
		acceptor.setHandler(minaServerHandle);
		try {
			// 綁定端口
			acceptor.bind(new InetSocketAddress(8081));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	public static void main(String args[]) {
		new ServerNetwork().init();
	}
}
 
        接下來,我們來編寫處理Mina網絡層回調的Handler,它在連接,打開,發送,接收,關閉,異常等情況下都會調用其回調
// 負責處理網絡層回調的類,需要繼承IoHandlerAdapter 
public class MinaServerHandle extends IoHandlerAdapter {
	@Override
	public void messageReceived(IoSession ioSession, Object message) {
		System.out.println("從輸入留讀入時調用");
	}
	
	@Override
	public void sessionClosed(IoSession session) throws Exception {
		System.out.println("關閉連接時調用");
	}
	
	@Override
	public void exceptionCaught(IoSession session, Throwable cause) {
		System.out.println("發生異常時調用");
	}
	
	@Override
	public void sessionCreated(IoSession session) throws Exception {
		System.out.println("客戶端發起一個新連接時調用");
	}
	
	@Override
	public void sessionOpened(IoSession session) throws Exception {
		System.out.println("連接開啟時調用");
	}
	
	@Override
	public void sessionIdle(IoSession session, IdleStatus status) throws Exception {
		System.out.println("連接空閑的時調用");
	}
	
	@Override
	public void messageSent(IoSession session, Object message) throws Exception {
		System.out.println("往輸出流寫數據時調用");
	}
}
 
        到此,一個簡單的Mina非阻塞連接就建立起來了。當客戶端發來新的數據時,會調用messageReceived方法;而服務器往客戶端發送時只需要直接對這個IOSession盡心write操作即可iosession.write("要發送的內容");
網絡連接是一種不穩定的連接,丟包,亂序問題還能通過程序來解決,但是斷線問題,就沒辦法了。所以,服務器與客戶端的一些重要的通信,必須要保證斷線也不會丟失,至少要保證知道對方未收到的問題,進行后續的處理。
在這里告訴大家一個服務器端向IO流寫的小技巧,帖主在剛開始使用Mina的時候還學習的太少,不知道Mina在TCP發送數據時是有回調函數的,即“發送成功”、”發送失敗“等等信息,還自己寫了個客戶端的”收到某消息回復“的接口╮(╯﹏╰)╭
 先介紹一下如何查看發送是否成功。(代碼來自開源項目《迷你微信》服務器)
iosession.write("WTF");
WriteFuture writeFuture = user.ioSession.write(packetWillSend);
writeFuture.addListener(new IoFutureListener<IoFuture>() {
	@Override
	public void operationComplete(IoFuture future) {
		if (((WriteFuture) future).isWritten()) {
			// 發送成功
		} else {
			// 發送失敗
		}
	}
});
 
        簡單的說就是添加一個監聽,然后在有結果(成功?失敗)的時候,Mina將會自動調用operationComplete方法,再根據IoFuture獲取結果。

