1. 程式人生 > >Apache MINA網路通訊框架

Apache MINA網路通訊框架

基本介紹:

Apache MINA 2是一個開發高效能和高可伸縮性網路應用程式的網路應用框架。它提供了一個抽象的事件驅動的非同步API,可以使用TCP/IP、UDP/IP、串列埠和虛擬機器內部的管道等傳輸方式。Apache MINA 2可以作為開發網路應用程式的一個良好基礎。

Mina 的API 將真正的網路通訊與我們的應用程式隔離開來,你只需要關心你要傳送、

接收的資料以及你的業務邏輯即可。

mina的基本架構:

在圖中的模組鏈中,IoService 便是應用程式的入口,相當於我們前面程式碼中的 IoAccepter,IoAccepter 便是 IoService 的一個擴充套件介面。IoService 介面可以用來新增多個 IoFilter,這些 IoFilter 符合責任鏈模式並由 IoProcessor 執行緒負責呼叫。而 IoAccepter 在 ioService 介面的基礎上還提供繫結某個通訊埠以及取消繫結的介面。ioHandler則為應用邏輯處理類。

主要類以及介面:

(1.)IoService:這個介面在一個執行緒上負責套接字的建立,擁有自己的Selector,監

聽是否有連線被建立。

(2.)IoProcessor:這個介面在另一個執行緒上負責檢查是否有資料在通道上讀寫,也就是

說它也擁有自己的Selector,這是與我們使用JAVA NIO編碼時的一個不同之處,

通常在JAVA NIO編碼中,我們都是使用一個Selector,也就是不區分IoService

與IoProcessor兩個功能介面。另外,IoProcessor負責呼叫註冊在IoService上

的過濾器,並在過濾器鏈之後呼叫IoHandler。

(3.)IoFilter:這個介面定義一組攔截器,這些攔截器可以包括日誌輸出、黑名單過濾、

資料的編碼(write方向)與解碼(read方向)等功能,其中資料的encode與decode

是最為重要的、也是你在使用Mina時最主要關注的地方。

(4.)IoHandler:這個介面負責編寫業務邏輯,也就是接收、傳送資料的地方。

(5.)IoSession:Session可以理解為伺服器與客戶端的特定連線,該連線由伺服器地址、埠以及客戶端地址、埠來決定。客戶端發起請求時,指定伺服器地址和埠,客戶端也會指定或者根據網路路由資訊自動指定一個地址、自動分配一個埠。這個地址、埠對構成一個Session。Session是伺服器端對這種連線的抽象,MINA對其進行了封裝,定義了IoSession介面,用來代表客戶端與伺服器的連線,在伺服器端來指代客戶端,實現對客戶端的操作、繫結與客戶端有關的資訊與物件。通過利用Session的這個概念,編寫程式時就可以在伺服器端非常方便地區分出是當前處理的是哪個客戶端的請求、維持客戶端的狀態資訊、可以實現客戶端之間相互通訊。

一圖勝千言,MINA的核心類圖:

服務端程式碼大致如下:

Java程式碼

  1. //初始化Acceptor—可以不指定執行緒數量,MINA2裡面預設是CPU數量+2
  2. //是你的工作主執行緒
  3. NioSocketAcceptor acceptor = new NioSocketAcceptor(5);
  4. //建立執行緒池
  5. java.util.concurrent.Executor threadPool = newFixedThreadPool(1500);
  6. //加入過濾器(Filter)到Acceptor
  7. acceptor.getFilterChain().addLast(“exector”, new ExecutorFilter(threadPool));
  8. //編碼解碼器
  9. acceptor.getFilterChain().addLast(“codec”,new ProtocolCodecFilter(new WebDecoder(),new XmlEncoder()));
  10. //日誌
  11. LoggingFilter filter = new LoggingFilter();
  12. filter.setExceptionCaughtLogLevel(LogLevel.DEBUG);
  13. filter.setMessageReceivedLogLevel(LogLevel.DEBUG);
  14. filter.setMessageSentLogLevel(LogLevel.DEBUG);
  15. filter.setSessionClosedLogLevel(LogLevel.DEBUG);
  16. filter.setSessionCreatedLogLevel(LogLevel.DEBUG);
  17. filter.setSessionIdleLogLevel(LogLevel.DEBUG);
  18. filter.setSessionOpenedLogLevel(LogLevel.DEBUG);
  19. acceptor.getFilterChain().addLast(“logger”, filter);
  20. //設定的是主服務監聽的埠可以重用
  21. acceptor.setReuseAddress(true);
  22. //設定每一個非主監聽連線的埠可以重用
  23. acceptor.getSessionConfig().setReuseAddress(true);
  24. //MINA2中,當啟動一個服務端的時候,要設定初始化緩衝區的長度,如果不設定這個值,系統預設為2048,當客戶端發過來的訊息超過設定值的時候,
  25. //MINA2的機制是分段接受的,將字元是放入緩衝區中讀取,所以在讀取訊息的時候,需要判斷有多少次。這樣的好處就是可以節省通訊的流量。
  26. //設定輸入緩衝區的大小
  27. acceptor.getSessionConfig().setReceiveBufferSize(1024);
  28. //設定輸出緩衝區的大小
  29. acceptor.getSessionConfig().setSendBufferSize(10240);
  30. //設定為非延遲傳送,為true則不組裝成大包傳送,收到東西馬上發出
  31. acceptor.getSessionConfig().setTcpNoDelay(true);
  32. //設定主服務監聽埠的監聽佇列的最大值為100,如果當前已經有100個連線,再新的連線來將被伺服器拒絕
  33. acceptor.setBacklog(100);
  34. acceptor.setDefaultLocalAddress(new InetSocketAddress(port));
  35. //加入處理器(Handler)到Acceptor
  36. acceptor.setHandler(new YourHandler());
  37. acceptor.bind();
        //初始化Acceptor—可以不指定執行緒數量,MINA2裡面預設是CPU數量+2  
        //是你的工作主執行緒   
        NioSocketAcceptor acceptor = new NioSocketAcceptor(5);
        //建立執行緒池
        java.util.concurrent.Executor threadPool = newFixedThreadPool(1500);
        //加入過濾器(Filter)到Acceptor         
        acceptor.getFilterChain().addLast("exector", new ExecutorFilter(threadPool));
        //編碼解碼器
        acceptor.getFilterChain().addLast("codec",new ProtocolCodecFilter(new WebDecoder(),new XmlEncoder()));
        //日誌      
        LoggingFilter filter = new LoggingFilter();
        filter.setExceptionCaughtLogLevel(LogLevel.DEBUG);
        filter.setMessageReceivedLogLevel(LogLevel.DEBUG);
        filter.setMessageSentLogLevel(LogLevel.DEBUG);
        filter.setSessionClosedLogLevel(LogLevel.DEBUG);
        filter.setSessionCreatedLogLevel(LogLevel.DEBUG);
        filter.setSessionIdleLogLevel(LogLevel.DEBUG);
        filter.setSessionOpenedLogLevel(LogLevel.DEBUG);
        acceptor.getFilterChain().addLast("logger", filter);
        //設定的是主服務監聽的埠可以重用
        acceptor.setReuseAddress(true);
        //設定每一個非主監聽連線的埠可以重用        
        acceptor.getSessionConfig().setReuseAddress(true);
        //MINA2中,當啟動一個服務端的時候,要設定初始化緩衝區的長度,如果不設定這個值,系統預設為2048,當客戶端發過來的訊息超過設定值的時候,
        //MINA2的機制是分段接受的,將字元是放入緩衝區中讀取,所以在讀取訊息的時候,需要判斷有多少次。這樣的好處就是可以節省通訊的流量。
        //設定輸入緩衝區的大小
        acceptor.getSessionConfig().setReceiveBufferSize(1024);
        //設定輸出緩衝區的大小
        acceptor.getSessionConfig().setSendBufferSize(10240);
        //設定為非延遲傳送,為true則不組裝成大包傳送,收到東西馬上發出         
        acceptor.getSessionConfig().setTcpNoDelay(true);
        //設定主服務監聽埠的監聽佇列的最大值為100,如果當前已經有100個連線,再新的連線來將被伺服器拒絕         
        acceptor.setBacklog(100);
        acceptor.setDefaultLocalAddress(new InetSocketAddress(port));
        //加入處理器(Handler)到Acceptor         
        acceptor.setHandler(new YourHandler());
        acceptor.bind();

客戶端程式碼大致如下:

客戶端的初始化和伺服器端其實是一樣的,就是初始化類不一樣,客戶端是作為傳送者的。

Java程式碼

  1. SocketConnector connector = new NioSocketConnector();
  2. connector.getFilterChain().addLast(“codec”, new ProtocolCodecFilter(new XmlCodecFactory(Charset.forName(charsetName), null, sertType)));
  3. //指定執行緒池
  4. connector.getFilterChain().addLast(“executor”, new ExecutorFilter());
  5. //指定業務處理類
  6. connector.setHandler(this);
        SocketConnector connector = new NioSocketConnector();
        connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(new XmlCodecFactory(Charset.forName(charsetName), null, sertType)));
        //指定執行緒池
        connector.getFilterChain().addLast("executor", new ExecutorFilter());
        //指定業務處理類
        connector.setHandler(this);

在IoHandler中定義了一些事件方法,比如messageReceived,sessionOpend,sessionCreated,exceptionCaught等,使用者只需要在方法內部實現對應的處理邏輯即可。

心跳機制:

mina自身帶的心跳機制好處在於,它附加了處理,讓心跳訊息不會傳到業務層,在底層就完成了。

事件模型:

MINA可以看成是事件驅動的。通常在網路通訊中,可以將整個過程劃分為幾個基本的階段,如建立連線、資料通訊、關閉連線。

資料通訊一般包括資料的傳送和接收,由於在通訊過程中,可能要多次傳送和接收資料,以進行不同的業務互動。

不可能一直都接收和傳送資料,因此就有Idle出現,在MINA中,如果在設定的時間內沒有資料傳送或接收,那麼就會觸發一個Idle事件。

附錄:對與協議的理解,摘自ppt

http協議
對應於應用層
tcp協議
對應於傳輸層
ip協議
對應於網路層
三者本質上沒有可比性。 何況HTTP協議是基於TCP連線的。
TCP/IP是傳輸層協議,主要解決資料如何在網路中傳輸;而HTTP是應用層協議,主要解決如何包裝資料。
我們在傳輸資料時,可以只使用傳輸層(TCP/IP),但是那樣的話,由於沒有應用層,便無法識別資料內容,如果想要使傳輸的資料有意義,則必須使用應用層協議,應用層協議很多,有HTTP、FTP、TELNET等等,也可以自己定義應用層協議。WEB使用HTTP作傳輸層協議,以封裝HTTP文字資訊,然後使用TCP/IP做傳輸層協議將它傳送到網路上。

Socket是對TCP/IP協議的封裝,Socket本身並不是協議,而是一個呼叫介面(API),通過Socket,我們才能使用TCP/IP協議。

這也就不難理解為什麼有些內部的系統呼叫採用socket,而不是http。

本身web的這種系統,HTTP已經將報文資訊封裝好了。各種JEE的WEB框架,都能夠直接獲取報文中的資訊,而socket方式,可以雙方很方便的自己定義報文的內容,加密方式等等。

URL:應用層

SOCKET
:網路傳輸層

Socket(套接字)

是一種基於網路傳輸層的遠端程序間通訊程式設計介面,有作業系統提供一個套接字包含,主機名、埠號兩個部分。其中埠號是0~65535之間的一個整數。通常小於1024的埠號被統一分配給特定的網路服務,如ftp服務,21;http服務, 80;SMTP服務,25;POP3服務,110;telnet服務,23等等

套接字(socket)是通訊的基石,是支援TCP/IP協議的網路通訊的基本操作單元。它是網路通訊過程中端點的抽象表示,包含進行網路通訊必須的五種資訊:連線使用的協議,本地主機的IP地址,本地程序的協議埠,遠地主機的IP地址,遠地程序的協議埠。

應用層通過傳輸層進行資料通訊時,TCP會遇到同時為多個應用程式程序提供併發服務的問題。多個TCP連線或多個應用程式程序可能需要通過同一個
TCP協議埠傳輸資料。為了區別不同的應用程式程序和連線,許多計算機作業系統為應用程式與TCP/IP協議互動提供了套接字(Socket)介面。

由於通常情況下Socket連線就是TCP連線,因此Socket連線一旦建立,通訊雙方即可開始相互發送資料內容,直到雙方連線斷開。但在實際網路應用中,客戶端到伺服器之間的通訊往往需要穿越多箇中間節點,例如路由器、閘道器、防火牆等,大部分防火牆預設會關閉長時間處於非活躍狀態的連線而導致
Socket 連線斷連,因此需要通過輪詢告訴網路,該連線處於活躍狀態。
而HTTP連線使用的是“請求—響應”的方式,不僅在請求時需要先建立連線,而且需要客戶端向伺服器發出請求後,伺服器端才能回覆資料。

很多情況下,需要伺服器端主動向客戶端推送資料,保持客戶端與伺服器資料的實時與同步。此時若雙方建立的是Socket連線,伺服器就可以直接將資料傳送給客戶端;若雙方建立的是HTTP連線,則伺服器需要等到客戶端傳送一次請求後才能將資料傳回給客戶端,因此,客戶端定時向伺服器端傳送連線請求,不僅可以保持線上,同時也是在“詢問”伺服器是否有新的資料,如果有就將資料傳給客戶端。