本blog主要介紹:
1. Codec 編解碼器
2. Decoder 解碼器
3. Encoder 編碼器服務器
netty提供了強大的編解碼器框架,使得咱們編寫自定義的編解碼器很容易,也容易封裝個重用。網絡
在網絡應用中須要實現某種編解碼器,將原始字節數據與自定義的消息對象進行互相轉換。網絡中都是以字節碼的數據形式來傳輸數據的,服務器編碼數據後發送到客戶端,客戶端須要對數據進行解碼。編解碼器由兩部分組成:編碼器、解碼器。
解碼器:負責將消息從字節或其餘序列形式轉成指定的消息對象;
編碼器:將消息對象轉成字節或其餘序列形式在網絡上傳輸。
編碼器和解碼器的結構很簡單,消息被編碼後解碼後會自動經過ReferenceCountUtil.release(message)釋放,若是不想釋放消息可使用ReferenceCountUtil.retain(message),這將會使引用數量增長而沒有消息發佈,大多數時候不須要這麼作。框架
其實,各類編解碼器的實現都是ChannelHandler的實現。 ide
Netty提供了豐富的解碼器抽象基類,咱們能夠很容易的實現這些基類來自定義解碼器。下面是解碼器的一個類型:編碼
解碼器負責解碼「入站」數據從一種格式到另外一種格式,解碼器處理入站數據是抽象ChannelInboundHandler的實現。實踐中使用解碼器很簡單,就是將入站數據轉換格式後傳遞到ChannelPipeline中的下一個ChannelInboundHandler進行處理;這樣的處理時很靈活的,咱們能夠將解碼器放在ChannelPipeline中,重用邏輯。spa
一般咱們須要將消息從 字節 解碼成 消息 或者從 字節 解碼成其餘的 序列化字節 。這是一個常見的任務,Netty提供了抽象基類,咱們可使用它們來實現。Netty中提供的ByteToMessageDecoder能夠將字節消息解碼成POJO對象,下面列出了ByteToMessageDecoder兩個主要方法:netty
decode(ChannelHandlerContext, ByteBuf, List<Object>)//這個方法是惟一的一個須要本身實現的抽象方法,做用是將ByteBuf數據解碼成其餘形式的數據。 decodeLast(ChannelHandlerContext, ByteBuf, List<Object>)//實際上調用的是decode(...)。
上圖顯示了從「入站」ByteBuf讀取bytes後由 ToIntegerDecoder 進行解碼,而後將解碼後的消息存入List集合中,而後傳遞到ChannelPipeline中的下一個ChannelInboundHandler。看下面ToIntegerDecoder的實現代碼:code
/** * Integer解碼器,ByteToMessageDecoder實現 * */ public class ToIntegerDecoder extends ByteToMessageDecoder { @Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { //接收到字節大於4個字節了就處理。 if(in.readableBytes() >= 4){ out.add(in.readInt()); } } }
ReplayingDecoder是byte-to-message解碼的一種特殊的抽象基類,byte-to-message解碼讀取緩衝區的數據以前須要檢查緩衝區是否有足夠的字節,使用ReplayingDecoder就無需本身檢查;若ByteBuf中有足夠的字節,則會正常讀取;若沒有足夠的字節則會中止解碼。也正由於這樣的包裝使得ReplayingDecoder帶有必定的侷限性。
• 不是全部的操做都被ByteBuf支持,若是調用一個不支持的操做會拋出DecoderException。
• ByteBuf.readableBytes()大部分時間不會返回指望值對象
若是你能忍受上面列出的限制,相比ByteToMessageDecoder,你可能更喜歡ReplayingDecoder。在知足需求的狀況下推薦使用ByteToMessageDecoder,由於它的處理比較簡單,沒有ReplayingDecoder實現的那麼複雜。ReplayingDecoder繼承於ByteToMessageDecoder,因此他們提供的接口是相同的。下面代碼是ReplayingDecoder的實現:blog
/** * Integer解碼器,ReplayingDecoder實現 */ public class ToIntegerReplayingDecoder extends ReplayingDecoder<Void> { @Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { out.add(in.readInt()); } }
將消息對象轉成消息對象但是使用MessageToMessageDecoder,它是一個抽象類,須要咱們本身實現其decode(…)。message-to-message同上面講的byte-to-message的處理機制同樣,看下圖:
實現代碼:
/** * 將接收的Integer消息轉成String類型,MessageToMessageDecoder實現 * @author c.k * */ public class IntegerToStringDecoder extends MessageToMessageDecoder<Integer> { @Override protected void decode(ChannelHandlerContext ctx, Integer msg, List<Object> out) throws Exception { out.add(String.valueOf(msg)); } }
解碼器是用來處理入站數據,Netty提供了不少解碼器的實現,能夠根據需求詳細瞭解。
Netty提供了一些基類,咱們能夠很簡單的編碼器。一樣的,編碼器有下面兩種類型:
相對解碼器,編碼器少了一個byte-to-byte的類型,由於出站數據這樣作沒有意義。編碼器的做用就是將處理好的數據轉成字節碼以便在網絡中傳輸。對照上面列出的兩種編碼器類型,Netty也分別提供了兩個抽象類:MessageToByteEncoder和MessageToMessageEncoder。下面是類關係圖:
MessageToByteEncoder是抽象類,咱們自定義一個繼承MessageToByteEncoder的編碼器只須要實現其提供的encode(…)方法。其工做流程以下圖:
實現代碼以下:
/** * 編碼器,將Integer值編碼成byte[],MessageToByteEncoder實現 */ public class IntegerToByteEncoder extends MessageToByteEncoder<Integer> { @Override protected void encode(ChannelHandlerContext ctx, Integer msg, ByteBuf out) throws Exception { out.writeInt(msg); } }
須要將消息編碼成其餘的消息時可使用Netty提供的MessageToMessageEncoder抽象類來實現。例如將Integer編碼成String,其工做流程以下圖:
代碼實現以下:
/** * 編碼器,將Integer編碼成String,MessageToMessageEncoder實現 */ public class IntegerToStringEncoder extends MessageToMessageEncoder<Integer> { @Override protected void encode(ChannelHandlerContext ctx, Integer msg, List<Object> out) throws Exception { out.add(String.valueOf(msg)); } }