netty的編解碼器介紹

本blog主要介紹: 
1. Codec 編解碼器 
2. Decoder 解碼器 
3. Encoder 編碼器服務器

netty提供了強大的編解碼器框架,使得咱們編寫自定義的編解碼器很容易,也容易封裝個重用。網絡

在網絡應用中須要實現某種編解碼器,將原始字節數據與自定義的消息對象進行互相轉換。網絡中都是以字節碼的數據形式來傳輸數據的,服務器編碼數據後發送到客戶端,客戶端須要對數據進行解碼。編解碼器由兩部分組成:編碼器、解碼器。 

解碼器:負責將消息從字節或其餘序列形式轉成指定的消息對象; 
編碼器:將消息對象轉成字節或其餘序列形式在網絡上傳輸。 

編碼器和解碼器的結構很簡單,消息被編碼後解碼後會自動經過ReferenceCountUtil.release(message)釋放,若是不想釋放消息可使用ReferenceCountUtil.retain(message),這將會使引用數量增長而沒有消息發佈,大多數時候不須要這麼作。框架


其實,各類編解碼器的實現都是ChannelHandler的實現。 ide

解碼器

Netty提供了豐富的解碼器抽象基類,咱們能夠很容易的實現這些基類來自定義解碼器。下面是解碼器的一個類型:編碼

  • 解碼字節到消息
  • 解碼消息到消息

解碼器負責解碼「入站」數據從一種格式到另外一種格式,解碼器處理入站數據是抽象ChannelInboundHandler的實現。實踐中使用解碼器很簡單,就是將入站數據轉換格式後傳遞到ChannelPipeline中的下一個ChannelInboundHandler進行處理;這樣的處理時很靈活的,咱們能夠將解碼器放在ChannelPipeline中,重用邏輯。spa

ByteToMessageDecoder

一般咱們須要將消息從 字節 解碼成 消息 或者從 字節 解碼成其餘的 序列化字節 。這是一個常見的任務,Netty提供了抽象基類,咱們可使用它們來實現。Netty中提供的ByteToMessageDecoder能夠將字節消息解碼成POJO對象,下面列出了ByteToMessageDecoder兩個主要方法:netty

decode(ChannelHandlerContext, ByteBuf, List<Object>)//這個方法是惟一的一個須要本身實現的抽象方法,做用是將ByteBuf數據解碼成其餘形式的數據。
decodeLast(ChannelHandlerContext, ByteBuf, List<Object>)//實際上調用的是decode(...)。
  • 例如服務器從某個客戶端接收到一個整數值的字節碼,服務器將數據讀入ByteBuf 並通過ChannelPipeline中的每一個 ChannelInboundHandle r進行處理,看下圖: 

這裏寫圖片描述 
上圖顯示了從「入站」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());  
        }  
    }  
}
  • 從上面的代碼可能會發現,咱們須要檢查ByteBuf讀以前是否有足夠的字節,這是與TCP黏包有關,若沒有這個檢查豈不更好?是的,Netty提供了這樣的處理容許byte-to-message解碼。除了ByteToMessageDecoder以外,Netty還提供了許多其餘的解碼接口。

ReplayingDecoder

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

將消息對象轉成消息對象但是使用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是抽象類,咱們自定義一個繼承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);
    }
}
  • MessageToMessageEncoder

須要將消息編碼成其餘的消息時可使用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));
    }
}
相關文章
相關標籤/搜索