解碼器LengthFieldBasedFrameDecoder, 從名字上可以猜測出來, 它是基於長度的解碼器.
Netty從TCP緩衝區中讀取字節, 把這些字節交給LengthFieldBasedFrameDecoder進行解碼, 解碼的操作是根據設定的規則, 根據規則, 從字節中解碼出來有意義的數據, 然後把數據再交給後續的Handler處理.
接下來看下, 它是如何根據規則解碼的.
在這裏插入圖片描述如上圖, 從網絡中讀取到的數據是基於流的, 而且是有方向的. 然而數據是沒有邊界的, 不知道從哪兒到哪兒是一個完整的數據, 下一個數據又是從哪個到哪個. 因此應用層需要設定規則, 根據規則就可以知道數據的邊界在哪兒.
在這裏插入圖片描述
如上圖, 便是根據設定的規則, 就可以’篩選’出來真正有意義的數據(data)在哪個. 而且允許每個data的長度是不一樣大小.
那麼就要說下這個規則是什麼了. 規則是由4個主要的屬性構成, lengthFieldOffset, lengthFieldLength, lengthAdjustment, initialBytesToStrip. 通過一個數據塊爲例介紹這4個屬性.
在這裏插入圖片描述如上圖, 從紅色箭頭指向的位置開始讀取數據.lengthFieldOffset表示長度字段的偏移量, 經過lengthFieldOffset之後, 箭頭指向了下一個位置. 如果lengthFieldOffset=3, 那麼箭頭需要向右邊走3個字節.
在這裏插入圖片描述接下來, lengthFieldLength表示長度字段的長度(好繞口). 如果lengthFieldLength=4, 那麼就會從上圖紅色位置向後讀取4個字節, 把4個字節裏面的內容作爲真正data的長度. 而且lengthFieldLength的取值不是任意的, 它只能取值1,2,3,4,8. 具體原因後面的源碼會說明.
在這裏插入圖片描述如上圖, 假如lengthFieldLength=4, 讀取4個字節的內容是0x00000010(十六進制表示), 十進制就是16, 也就是說, 數據data的長度是16個字節. 但是這裏稍等下, 需要介紹下一個關鍵屬性.
lengthAdjustment表示長度調整. 調整什麼呢? 還是要說下lengthFieldLength. lengthFieldLength裏面的內容是16, 雖然這個16表示長度, 但是它是表示真正數據data的長度,還是表示整個的長度呢, 或者其他呢. 因此要想真正表示真正數據data的長度, 必須用lengthFieldLength的內容值+lengthAdjustment的值. 如果lengthAdjustment=-5, 也就是用16+(-5)=11, 即從上圖紅色位置繼續向後讀取11個字節才能真正的把數據讀取完整, 讀取少了或多了都不行.
到這裏, 已經把一個完整的數據塊讀取完成了. 但是呢, 真正表示業務數據的內容是data部分.我們不想要前面的lengthFieldOffset和lengthFieldLength部分,這裏就需要使用initialBytesToStrip. 它表示跳過多少字節. 如果initialBytesToStrip=7, 那麼就是說要跳過7個字節, 把剩餘部分傳給下游的Handler繼續處理.
在這裏插入圖片描述以上就是4個主要屬性的解釋, 從源碼中拿一個具體的’案例’再溫習下.
在這裏插入圖片描述
從最左邊開始讀取數據, lengthFieldOffset=1, 那麼向後讀取1個字節, lengthFieldLength=2, 向後讀取2個字節, 讀取到的內容是0x0010(十六進制), 十進制就是16, 由於lengthAdjustment=-3, 因此16+(-3)=13, 於是繼續向後讀取13個字節. 就會把0xFE和"HELLO, WORLD"這13個字節讀取到. 到目前爲止, 讀取到的內容是0xCA0010FE和"HELLO, WORLD"共16個字節. 又initialBytesToStrip=3, 因此從16個字節的開頭跳過3個字節, 跳過了0xCA0010這3個字節, 最後剩下0xFE和"HELLO, WORLD"傳給了下游的Handler.