Java NIO框架MINA中文教程
=== 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() );
for( int 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