1. 程式人生 > >apache-Mina學習筆記

apache-Mina學習筆記

Apache Mina       mina是apache基於socket nio的一套框架。支援基於socket NIO庫的TCP/UDP應用程式的開發。 看原始碼發現,它底層使用了執行緒池的技術。即Mina本身實現了執行緒池,為了提高效率,可以通過自己寫連線池來使用Mina。這麼理解,連線池中有多個IoSession,對於每一個IoSession,Mina不會為一個IoSession起一個執行緒,而是利用執行緒池來處理,這是NIO的好處。 Mina TCP的幾個重要介面:
  • IoSession :是對底層連線的封裝,對應於當前客戶端到伺服器端的一個TCP連線例項。連線池中儲存著多個IoSession。
            這個介面有如下常用的方法:                   WriteFuture write(Object message):通過這個方法傳送資料。不會引起處理執行緒的阻塞。
  • IoHandler :這個介面負責編寫業務邏輯,也就是接收、傳送資料的地方。這也是實際開發過程中需要使用者自己編寫的部分程式碼。我們的專案中searchHub DataSource繼承了該介面
            void messageReceived(IoSession session, Object message) :             接收到訊息時呼叫的方法,message 是一個IoBuffer 類,如果你使用了協議編解碼器,那麼可以強制轉換為你需要的型別。
這裡簡單的介紹一下mina的框架:
  • IoService:這個介面是網路的入口,IoAcceptor和IoConnector都實現這個介面。
從名字上我們可以看得出來IoAcceptor是接受連結的(服務端),而IoConnector是用來連結的(客戶端) IoConnector用於與服務端建立連線,每連線一個服務端就建立一個執行緒。 這兩種執行緒都是通過執行緒池建立的。 這兩個都是繼承自IoService介面的抽象實現類AbstractIoService,在AbstractIoService原始碼中,有:
  • 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.執行結果




Demo參考地址: