1. 程式人生 > >Java NIO框架MINA中文教程

Java NIO框架MINA中文教程

      現在已經是World Wide Web的時代,無數的web應用框架被創造出來從而大大的提高了web開發的速度。拋開WWW的這個優勢,我們知道還有很多協議是HTTP協議所無法替代的。有時,我們仍然需要構造c/s應用來實現適當的協議。

 === MINA是什麼? ===
 你有沒有曾經使用java或者其他語言實現過某個協議棧?就像你所經歷過的那樣,編寫網路應用即使對於有經驗的開發者也不是容易的事情。這歸咎於以下幾個方面:

   * 沒有為開發者設計的合適的網路應用框架. 
     * 使你無法在有限的時間內建立你的應用. 
   * 網路I/O編碼,訊息的編/解碼,業務邏輯常常糾纏在一起. 
     * 使程式失去可維護性和可複用性 

   * 網路應用難於進行單元測試 
     * 你失去了敏捷性 

 MINA是一個網路應用框架,在不犧牲效能和可擴充套件性的前提下用於解決上面的所有問題。


 == I/O 層: 編寫一個 Echo Server ==
 MINA包含兩層:IO層和協議層。我們首先僅使用IO層來實現一個echo服務,因為協議層通常是建立在IO層之上的。 
 attachment:Arch1.gif
 上面的圖展示了MINA的IO層同客戶端的互動。IoAcceptor執行所有底層IO,將他們翻譯成抽象的IO事件,並把翻譯過的事件和關聯的IoSession
傳送給IoHandler。


 === IoSession ===
 attachment:IoSession.gif

  一個代表了IoSession程式同一個遠端實體的IO連線。通過IoSession,你可以寫出message到遠端實體,訪問session的配置,並且更改session的屬性。


 === IoHandler === 
 attachment:IoHandler.gif
   * sessionCreated: 當一個IO連線建立時被呼叫,這個方法在任何IO操作之前被呼叫,以便socket引數或session屬效能夠最先被設定。
   * sessionOpened: 在sessionCreated呼叫之後被呼叫。
   * sessionClosed: 當IO連線被關閉時被呼叫。
   * sessionIdle: 當在遠端實體和使用者程式之間沒有資料傳輸的時候被呼叫。

   * exceptionCaught: 當IoAcceptor 或者你的IoHandler.中出現異常時被呼叫。
   * messageReceived: 當接收到新的協議訊息時被呼叫。可以在這裡實現你的控制流程。
   * messageSent: 當用戶請求的訊息通過 IoSession#write(Object) 確實傳送後被呼叫。


 下面我們看看如何實現echo協議的IoHandler。
 === 實現 IoHandler 以及啟動程式碼 ===
 通常,應用需要繼承IoHandlerAdapter並實現需要的方法:


package org.apache.mina.examples.echoserver;
 
 
import org.apache.mina.common.ByteBuffer;
 
import org.apache.mina.common.IoHandlerAdapter;
 
import org.apache.mina.common.IoSession;
 
import org.apache.mina.common.TransportType;
 
import org.apache.mina.transport.socket.nio.SocketSessionConfig;
 
 
publicclass EchoProtocolHandler extends IoHandlerAdapter
 
{
     
publicvoid sessionCreated( IoSession session )
     
{
         
if (session.getTransportType() == TransportType.SOCKET) {
           ((SocketSessionConfig)session.getConfig()).setReceiveBufferSize(
2048);
     }

 
     
publicvoid exceptionCaught( IoSession session, Throwable cause )
     
{
         session.close();
     }

 
     
publicvoid messageReceived( IoSession session, Object message )
     
{
         
if (!(message instanceof ByteBuffer))
             
return;
      
         ByteBuffer rb 
= (ByteBuffer)message;
         
// Write the received data back to remote peer
         ByteBuffer wb = ByteBuffer.allocate( rb.remaining() );
         wb.put( rb );
         wb.flip();
         session.write( wb );
     }

 }

  剛剛我們使用MINA實現echo協議,現在我們將handler繫結到一個server埠上。
import java.net.InetSocketAddress;
 
import org.apache.mina.transport.socket.nio.SocketAcceptor;
 
import org.apache.mina.transport.socket.nio.SocketAcceptorConfig;
 
 
publicclass Main
 
{
     
/** Choose your favorite port number. */
     
privatestaticfinalint PORT =8080;
     
 
     
publicstaticvoid main( String[] args ) throws Exception
     
{
         SocketAcceptor acceptor 
=new SocketAcceptor();
         SocketAcceptorConfig defaultConfig 
=new SocketAcceptorConfig();
         defaultConfig.setReuseAddress(
true);
      
         
// Bind
         acceptor.bind(new InetSocketAddress(PORT), new EchoProtocolHandler(), defaultConfig);
 
         System.out.println( 
"Listening on port "+ PORT );
     }

 }


=== 新增IoFilters ===
 IoFilter提供了更加有力的方式來擴充套件MINA。它攔截所有的IO事件進行事件的預處理和後處理。你可以把它想象成Servlet的filters。IoFilter能夠實現以下幾種目的:

   * 事件日誌
   * 效能檢測
   * 資料轉換(e.g. SSL support)
   * 防火牆…等等
 attachment:Arch2.gif
 我們的echo協議handler不對任何IO事件進行日誌。我們可以通過新增一個filter來增加日誌能力。MINA提供了IoLoggingFilter來進行日誌。我們只要新增日誌filter到ServiceRegistry即可。
 .
 DefaultIoFilterChainBuilder chain 
= config.getFilterChain();
 addLogger(chain);
 .
 
 
privatestaticvoid addLogger( DefaultIoFilterChainBuilder chain ) throws Exception
 
{
     chain.addLast( 
"logger"new LoggingFilter() );
 }


 想使用SSL?MINA也提供了一個SSL的filter,但它需要JDK1.5。
 .
 DefaultIoFilterChainBuilder chain 
= config.getFilterChain();
 addLogger(chain);
 .
 
 
privatestaticvoid addSSLSupport( DefaultIoFilterChainBuilder chain )
     
throws Exception
 
{
     SSLFilter sslFilter 
=
         
new SSLFilter( BogusSSLContextFactory.getInstance( true ) );
     chain.addLast( 
"sslFilter", sslFilter );
     System.out.println( 
"SSL ON" );
 }

== 協議層: 實現反轉Echo協議 ==
 在上面我們通過簡單的echo server的例子學習瞭如何使用IO層,但是如果想實現複雜的如LDAP這樣的協議怎麼辦呢?它似乎是一個惡夢,因為IO層沒有幫助你分離‘message解析’和‘實際的業務邏輯(比如訪問一個目錄資料庫)’。MINA提供了一個協議層來解決這個問題。協議層將ByteBuffer事件轉換成高層的POJO事件:

 attachment:Arch3.gif

 使用協議層必須實現5個介面:ProtocolHandler, ProtocolProvider, ProtocolCodecFactory,
ProtocolEncoder, 和 ProtocolDecoder:

 attachment:ProtocolClasses.gif

 可能看上去有點麻煩,但是請注意ProtocolCodecFactory, ProtocolEncoder, 和
ProtocolDecoder是可以完全複用的;Apache的ASN1專案為MINA提供了ASN.1解碼器,更通用的解碼器如:XML、java物件序列化和簡單的文字將在MINA的下一個版本中提供。一旦你實現了一個靈活的解碼器,你可以在未來的應用中複用它,即使你不打算複用你的解碼器,MINA也提供了一個很簡單的方法來實現複雜的協議。(請參考高階主題)
 在這一章中,我們新增一個‘反轉’server,它用於反轉它接到的所有文字,我們通過它來示範如何編寫一個協議層。



 === ProtocolSession ===
 attachment:ProtocolSession.gif
 ProtocolSession同IO層的IoSession同樣繼承自Session。就像前面提到的,你只需撰寫面向POJO的message而不是ByteBuffer的。ProtocolEncoder
將message物件解釋成ByteBuffers以便IO層能夠將他們輸出到socket。

 === ProtocolHandler ===
 ProtocolHandler類似於IO層的IoHandler.dataRead和dataWritten方法被替換成messageReceived和messageSent。這是因為ProtocolDecoder
已經將IO層接收到的 ByteBuffers轉換成了message物件。
package org.apache.mina.examples.reverser;
 
 
import org.apache.mina.common.IoHandler;
 
import org.apache.mina.common.IoHandlerAdapter;
 
import org.apache.mina.common.IoSession;
 
 
publicclass ReverseProtocolHandler extends IoHandlerAdapter
 
{
     
publicvoid exceptionCaught( IoSession session, Throwable cause )
     
{
         
// Close connection when unexpected exception is caught.
         session.close();
     }

 
     
publicvoid messageReceived( IoSession session, Object message )
     
{
         
// Reverse received string
         String str = message.toString();
         StringBuffer buf 
=new StringBuffer( str.length() );
         
forint i = str.length()  1; i >=0; i )
         
{
             buf.append( str.charAt( i ) );
         }

 
         
// and write it back.
         session.write( buf.toString() );
     }

 }


 === ProtocolEncoder 和 ProtocolDecoder ===
 attachment:ProtocolCodec.gif
 ProtocolEncoder 和ProtocolDecoder只有一個方法。ProtocolEncoder將message物件轉換成一個ByteBuffer,而ProtocolDecoder將一個ByteBuffer轉換成message物件。下面我們將學習如何實現這些介面。要實現反轉協議要實作的唯一介面就是ProtocolProvider。它非常簡單:
 (注:Provider用於在一個統一的類中提供該協議相關的Handler、Decoder和Encoder。)

package org.apache.mina.examples.reverser;
 
 
import org.apache.mina.protocol.*;
 
 
/**
  * {
@link ProtocolProvider} implementation for reverser server protocol.
 
*/

 
publicclass ReverseProtocolProvider implements ProtocolProvider
 
{
     
// Protocol handler is usually a singleton.
privatestatic ProtocolHandler HANDLER =
 
new ReverseProtocolHandler();
 
     
// Codec factory is also usually a singleton.
privatestatic ProtocolCodecFactory CODEC_FACTORY =
 
new ProtocolCodecFactory()
     
{
         
public ProtocolEncoder newEncoder()
         
{
             
// Create a new encoder.
returnnew TextLineEncoder();
         }

 
         
public ProtocolDecoder newDecoder()
         
{
             
// Create a new decoder.
returnnew TextLineDecoder();
         }

相關推薦

Java NIO框架MINA中文教程

      現在已經是World Wide Web的時代,無數的web應用框架被創造出來從而大大的提高了web開發的速度。拋開WWW的這個優勢,我們知道還有很多協議是HTTP協議所無法替代的。有時,我們仍然需要構造c/s應用來實現適當的協議。 === MINA是什麼? ==

Java NIO框架Netty教程(十六)-ServerBootStrap啟動流程源碼分析

ucc ask pip 以及 梳理 學習曲線 owa pan server 有一段事件沒有更新文章了,各種原因都有吧。搬家的瑣事,搬家後的安逸呵呵。不過,OneCoder明白,絕不能放松。對於Netty的學習,也該稍微深入一點了。 所以,這次OneCoder花了幾天時間,仔

Java NIO框架Netty教程(九) Object對象編/解碼

log writer arr num context 不兼容 是的 pat .html 看到題目,有的同學可能會想,上回不是說過對象傳遞了嗎?是的,只是在Java NIO框架Netty教程(八) Object對象傳遞中,我們只是介紹如何使用Netty提供的編/解碼工具,完成

Java NIO框架Netty教程(四) ChannelBuffer

ets 認識 buffers 不想 http 觸發 getch 我們 基於 在學字符串消息收發(http://www.it165.net/pro/html/201207/3174.html)的時候,已經提到過。ChannelBuffer是Netty中非常重要的概念。所有消息

Java NIO框架Netty教程(三) 字符串消息收發

view itl col ioc 啟動 type lines nta tty 了解了Netty的基本概念(http://www.it165.net/pro/html/201207/3173.html),開發起來應該會順手很多。 在“Hello World(http://w

Java NIO框架Netty教程(一) – Hello Netty

tex highlight bsp ret 開發 包括 tor 習慣 事件機制 先啰嗦兩句,如果你還不知道Netty是做什麽的能做什麽。那可以先簡單的搜索了解一下。我只能說Netty是一個NIO的框架,可以用於開發分布式的Java程序。具體能做什麽,各位可以盡量發揮想象。技

Java NIO框架Netty教程(三)

瞭解了Netty的基本概念,開發起來應該會順手很多。在“Hello World”程式碼中,我們只是在完成繫結的時候,在各自的本地列印了簡單的資訊,並沒有客戶端和服務端的訊息傳遞。這個肯定是最基本的功能。在上程式碼之前,先補充一個Netty中重要的

Java NIO框架Netty教程(八)

說了這麼多廢話,才提到物件的傳輸,不知道您是不是已經不耐煩了。一個系統內部的訊息傳遞,沒有物件傳遞是不太現實的。下面就來說說,怎麼傳遞物件。 如果,您看過前面的介紹,如果您善於專注本質,勤于思考。您應該也會想到,我們說過,Netty的訊息傳遞都

Java NIO框架Netty教程(五)

週末是最好的學習時間,不過這週末收房子,可想而知事情自然也不會少。這段時間的週末,可能很少有時間學習了。見縫插針吧。 不說廢話了,好好學習。上回通過程式碼理解了Netty底層資訊的流的傳遞機制,不過只是一個感性上的認識。教會你應該如何使用和使用

Java NIO框架Netty教程(十六)

有一段事件沒有更新文章了,各種原因都有吧。搬家的瑣事,搬家後的安逸呵呵。不過,OneCoder明白,絕不能放鬆。對於Netty的學習,也該稍微深入一點了。 所以,這次OneCoder花了幾天時間,仔細梳理了一下Netty的原始碼,總結了一下Se

Java NIO框架Netty教程(十四)

OneCoder這個週末搬家,並且新家目前還沒有網路,本週的翻譯的任務尚未完成,下週一起補上,先上一篇OIO和NIO對比的小研究。 Netty中不光支援了Java中NIO模型,同時也提供了對OIO模型的支援。(New IO vs Old IO)

Java NIO框架Netty教程(十)

如果您一直關注OneCoder,我們之前有兩篇文章介紹關於Netty訊息連續收發的問題。( 《Java NIO框架Netty教程(五)- 訊息收發次數不匹配的問題 》、《 Java NIO框架Netty教程(七)-再談收發資訊次數問題 》)。如果

Java NIO框架Netty教程(四)

Unfortunately, the buffer of a stream-based transport is not a queue of packets but a queue of bytes. It means, even if you sent two messages

Java NIO框架Netty教程(二)

“Hello World”的程式碼固然簡單,不過其中的幾個重要概念(類)和 Netty的工作原理還是需要簡單明確一下,至少知道其是負責什。方便自己以後更靈活的使用和擴充套件。 宣告,筆者一介碼農,不會那麼多專業的詞彙和縮寫,只能以最簡單蒼白的

Java NIO框架Netty教程(十二)

寫在前面:對Netty併發問題的測試和解決完全超出了我的預期,想說的東西越來越多。所以才出現這個中篇,也就是說,一定會有下篇。至於問題點的發現,OneCoder也在努力驗證中。 繼續併發的問題。在《Java NIO框架Netty教程(十一)-併

Java NIO框架Netty教程(一)

先囉嗦兩句,如果你還不知道Netty是做什麼的能做什麼。那可以先簡單的搜尋瞭解一下。我只能說Netty是一個NIO的框架,可以用於開發分散式的Java程式。具體能做什麼,各位可以儘量發揮想象。技術,是服務於人而不是侷限住人的。 Netty的簡介

Java NIO框架Netty教程(十一)

之前更新了幾篇關於JVM研究的文章,其實也是在做本篇文章驗證的時候,跑的有點遠,呵呵。迴歸Netty教程,這次要講的其實是針對一個問題的研究和驗證結論。另外,最近工作比較忙,所以可能會分文章更新一些階段性的成果,而不是全部彙總更新,以免間隔過久。

Java NIO框架Netty教程(十三)

在上節(《Java NIO框架Netty教程(十二)-併發訪問測試(中)》),我們從各個角度對Netty併發的場景進行了測試。這節,我們將重點關注上節最後提到的問題。在多執行緒併發訪問的情況下,會出現 警告: EXCEPTION, please

Java NIO框架Netty教程(十七)

最近很多人問我有沒有Netty4的Hello World樣例,很早之前知道Netty要出4,當時只知道4的包名完全邊了,因為Netty從JBoss中獨立出來了,並採用了新的netty.io的域名,但是沒想到程式碼也有這麼大的調整。 既然答應

Java NIO框架Netty教程(七)

經過簡單的瞭解,筆者大膽的猜測和”武斷”一下該問題的原因。 首先,Selector機制讓我們註冊一個感興趣的事件,然後只要有該事件發生,就會傳遞給接收端。我們寫了三次,接收端一定會出發三次的。 然後,Netty實現機制裡,有個Buffer