netty系列之:内置的Frame detection
文章目錄
- 簡介
- Frame detection
- DelimiterBasedFrameDecoder
- FixedLengthFrameDecoder
- LengthFieldBasedFrameDecoder
- LineBasedFrameDecoder
- 總結
簡介
上篇文章我們講到了netty中怎么自定義編碼和解碼器,但是自定義實現起來還是挺復雜的,一般沒有特殊必要的情況下,大家都希望越簡單越好,其難點就是找到ByteBuf中的分割點,將ByteBuf分割成為一個個的可以處理的單元。今天本文講講netty中自帶的分割處理機制。
Frame detection
在上一章,我們提到了需要有一種手段來區分ByteBuf中不同的數據,也就是說找到ByteBuf中不同數據的分割點。如果首先將ByteBuf分割成一個個的獨立的ByteBuf,再對獨立的ByteBuf進行處理就會簡單很多。
netty中提供了4個分割點的編碼器,我們可以稱之為Frame detection,他們分別是DelimiterBasedFrameDecoder, FixedLengthFrameDecoder, LengthFieldBasedFrameDecoder, 和 LineBasedFrameDecoder。
這幾個類都是ByteToMessageDecoder的子類,接下來我們一一進行介紹。
DelimiterBasedFrameDecoder
首先是DelimiterBasedFrameDecoder,看名字就知道這個是根據delimiter對bytebuf進行分割的解碼器。什么是delimiter呢?
netty中有一個Delimiters類,專門定義分割的字符,主要有兩個delimiter,分別是nulDelimiter和lineDelimiter:
public static ByteBuf[] nulDelimiter() {return new ByteBuf[] {Unpooled.wrappedBuffer(new byte[] { 0 }) };}public static ByteBuf[] lineDelimiter() {return new ByteBuf[] {Unpooled.wrappedBuffer(new byte[] { '\r', '\n' }),Unpooled.wrappedBuffer(new byte[] { '\n' }),};}nullDelimiter用來處理0x00,主要用來處理Flash XML socket或者其他的類似的協議。
lineDelimiter用來處理回車和換行符,主要用來文本文件的處理中。
對于DelimiterBasedFrameDecoder來說,如果有多個delimiter的話,會選擇將ByteBuf分割最短的那個,舉個例子,如果我們使用DelimiterBasedFrameDecoder(Delimiters.lineDelimiter()) ,因為lineDelimiter中實際上有兩個分割方式,回車+換行或者換行,如果遇到下面的情況:
+--------------+| ABC\nDEF\r\n |+--------------+DelimiterBasedFrameDecoder會選擇最短的分割結果,也就說將上面的內容分割成為:
+-----+-----+| ABC | DEF |+-----+-----+而不是
+----------+| ABC\nDEF |+----------+FixedLengthFrameDecoder
這個類會將ByteBuf分成固定的長度,比如收到了下面的4塊byte信息:
+---+----+------+----+| A | BC | DEFG | HI |+---+----+------+----+如果使用一個FixedLengthFrameDecoder(3) ,則會將上面的ByteBuf分成下面的幾個部分:
+-----+-----+-----+| ABC | DEF | GHI |+-----+-----+-----+LengthFieldBasedFrameDecoder
這個類就更加靈活一點,可以根據數據中的length字段取出后續的byte數組。LengthFieldBasedFrameDecoder非常靈活,它有4個屬性來控制他們分別是lengthFieldOffset、lengthFieldLength、lengthAdjustment和initialBytesToStrip。
lengthFieldOffset是長度字段的起始位置,lengthFieldLength是長度字段本身的長度,lengthAdjustment是對目標數據長度進行調整,initialBytesToStrip是解密過程中需要刪除的byte數目。理解不了?沒關系,我們來舉幾個例子。
首先看一個最簡單的:
lengthFieldOffset = 0lengthFieldLength = 2lengthAdjustment = 0initialBytesToStrip = 0 BEFORE DECODE (14 bytes) AFTER DECODE (14 bytes)+--------+----------------+ +--------+----------------+| Length | Actual Content |----->| Length | Actual Content || 0x000C | "HELLO, WORLD" | | 0x000C | "HELLO, WORLD" |+--------+----------------+ +--------+----------------+上面的設置表示,length是從第0位開始的,長度是2個字節。其中Ox00C=12, 這也是“HELLO, WORLD” 的長度。
如果不想要Length字段,可以通過設置initialBytesToStrip把length刪除:
lengthFieldOffset = 0lengthFieldLength = 2lengthAdjustment = 0initialBytesToStrip = 2 (= length 字段的長度)BEFORE DECODE (14 bytes) AFTER DECODE (12 bytes)+--------+----------------+ +----------------+| Length | Actual Content |----->| Actual Content || 0x000C | "HELLO, WORLD" | | "HELLO, WORLD" |+--------+----------------+ +----------------+lengthAdjustment是對Length字段的值進行調整,因為在有些情況下Length字段可能包含了整條數據的長度,也就是Length+內容,所以需要在解析的時候進行調整,比如下面的例子,真實長度其實是0x0C,但是傳入的卻是0x0E,所以需要減去Length字段的長度2,也就是將lengthAdjustment設置為-2。
lengthFieldOffset = 0lengthFieldLength = 2lengthAdjustment = -2 (= Length字段的長度)initialBytesToStrip = 0BEFORE DECODE (14 bytes) AFTER DECODE (14 bytes)+--------+----------------+ +--------+----------------+| Length | Actual Content |----->| Length | Actual Content || 0x000E | "HELLO, WORLD" | | 0x000E | "HELLO, WORLD" |+--------+----------------+ +--------+----------------+LineBasedFrameDecoder
LineBasedFrameDecoder專門處理文本文件中的一行結束。也就是 “\n” 和 “\r\n”,他和DelimiterBasedFrameDecoder很類似,但是DelimiterBasedFrameDecoder更加通用。
總結
有了上面4個Frame detection裝置之后,就可以在pipline中首先添加這些Frame detection,然后再添加自定義的handler,這樣在自定義的handler中就不用考慮讀取ByteBuf的長度問題了。
比如在StringDecoder中,如果已經使用了 LineBasedFrameDecoder , 那么在decode方法中可以假設傳入的ByteBuf就是一行字符串,那么可以直接這樣使用:
protected void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception {out.add(msg.toString(charset));}是不是很簡單?
本文已收錄于 http://www.flydean.com/15-netty-buildin-frame-detection/
最通俗的解讀,最深刻的干貨,最簡潔的教程,眾多你不知道的小技巧等你來發現!
歡迎關注我的公眾號:「程序那些事」,懂技術,更懂你!
總結
以上是生活随笔為你收集整理的netty系列之:内置的Frame detection的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: netty系列之:自定义编码和解码器要注
- 下一篇: netty系列之:netty中的懒人编码