最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Netty解碼器LengthFieldBasedFrameDecoder詳解

 更新時間:2025年05月22日 15:47:55   作者:碼靈  
這篇文章主要介紹了Netty解碼器LengthFieldBasedFrameDecoder的使用方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教

Netty解碼器LengthFieldBasedFrameDecoder

解碼器LengthFieldBasedFrameDecoder,從名字上可以猜測出來,它是基于長度的解碼器.

Netty從TCP緩沖區(qū)中讀取字節(jié),把這些字節(jié)交給LengthFieldBasedFrameDecoder進行解碼,解碼的操作是根據設定的規(guī)則,根據規(guī)則,從字節(jié)中解碼出來有意義的數據,然后把數據再交給后續(xù)的Handler處理.

接下來看它是如何根據規(guī)則解碼的

如上圖,從網絡中讀取到的數據是基于流的,而且是有方向的.

然而數據是沒有邊界的,不知道從哪兒到哪兒是一個完整的數據,下一個數據又是從哪個到哪個.

因此應用層需要設定規(guī)則,根據規(guī)則就可以知道數據的邊界在哪兒.

如上圖,便是根據設定的規(guī)則,就可以’篩選’出來真正有意義的數據(data)在哪個. 而且允許每個data的長度是不一樣大小.

就要說下這個規(guī)則是什么了

規(guī)則是由4個主要的屬性構成,lengthFieldOffset,lengthFieldLength,lengthAdjustment,initialBytesToStrip.

通過一個數據塊為例介紹這4個屬性.

如上圖,從紅色箭頭指向的位置開始讀取數據.

lengthFieldOffset表示長度字段的偏移量,經過lengthFieldOffset之后,箭頭指向了下一個位置.

如果lengthFieldOffset=3,那么箭頭需要向右邊走3個字節(jié).

接下來,lengthFieldLength表示長度字段的長度(好繞口).

如果lengthFieldLength=4,那么就會從上圖紅色位置向后讀取4個字節(jié),把4個字節(jié)里面的內容作為真正data的長度.

而且lengthFieldLength的取值不是任意的,它只能取值1,2,3,4,8. 具體原因后面的源碼會說明.

如上圖,假如lengthFieldLength=4,讀取4個字節(jié)的內容是0x00000010(十六進制表示),十進制就是16,也就是說,數據data的長度是16個字節(jié). 但是這里稍等下,需要介紹下一個關鍵屬性.

lengthAdjustment表示長度調整. 調整什么呢? 還是要說下lengthFieldLength. lengthFieldLength里面的內容是16,雖然這個16表示長度,但是它是表示真正數據data的長度,還是表示整個的長度呢,或者其他呢. 因此要想真正表示真正數據data的長度,必須用lengthFieldLength的內容值+lengthAdjustment的值.

如果lengthAdjustment=-5,也就是用16+(-5)=11,即從上圖紅色位置繼續(xù)向后讀取11個字節(jié)才能真正的把數據讀取完整,讀取少了或多了都不行.

到這里,已經把一個完整的數據塊讀取完成了. 但是呢,真正表示業(yè)務數據的內容是data部分.我們不想要前面的lengthFieldOffset和lengthFieldLength部分,這里就需要使用initialBytesToStrip. 它表示跳過多少字節(jié).

如果initialBytesToStrip=7,那么就是說要跳過7個字節(jié),把剩余部分傳給下游的Handler繼續(xù)處理.

以上就是4個主要屬性的解釋,從源碼中拿一個具體的’案例’再溫習下.

從最左邊開始讀取數據,lengthFieldOffset=1,那么向后讀取1個字節(jié),lengthFieldLength=2,向后讀取2個字節(jié),讀取到的內容是0x0010(十六進制),十進制就是16,由于lengthAdjustment=-3,因此16+(-3)=13,于是繼續(xù)向后讀取13個字節(jié).

就會把0xFE和"HELLO,WORLD"這13個字節(jié)讀取到. 到目前為止,讀取到的內容是0xCA0010FE和"HELLO,WORLD"共16個字節(jié). 又initialBytesToStrip=3,因此從16個字節(jié)的開頭跳過3個字節(jié),跳過了0xCA0010這3個字節(jié),最后剩下0xFE和"HELLO,WORLD"傳給了下游的Handler.

源碼解讀如下,下面可以不看

Netty的源碼位置 io.netty.handler.codec.LengthFieldBasedFrameDecoder

LengthFieldBasedFrameDecoder繼承了ChannelInboundHandlerAdapter,因此當Netty讀取到網絡數據之后,再向下傳播數據的過程中,會調用到ByteToMessageDecoder的channelRead方法,channelRead方法內部會調用decode方法.

protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
 
        // 由于整個幀的長度 frameLength 大于 設定的maxFrameLength, 是需要跳過這個無效幀的.
 
        // 之前已經跳過了一部分數據, 由于之前不夠跳過, 現在又讀取到了數據, 那么需要繼續(xù)跳過剩下'欠'的數據
 
        if (discardingTooLongFrame) {
 
            discardingTooLongFrame(in);
 
        }
 
 
 
        // 在構造函數中定義了  lengthFieldEndOffset = lengthFieldOffset + lengthFieldLength
 
        // 它的意思是目前可以從網絡中讀取的實際字節(jié)數(in.readableBytes()) 小于 lengthFieldEndOffset , 無法處理 直接返回, 需要等待更多的數據.
 
        if (in.readableBytes() < lengthFieldEndOffset) {
 
            return null;
 
        }
 
 
 
        // in.readerIndex() 表示讀取上一個完整數據的最后下標
 
        int actualLengthFieldOffset = in.readerIndex() + lengthFieldOffset;
 
        // frameLength 表示獲取沒有調整前的數據幀長度 .  后面的邏輯要使用lengthAdjustment屬性調整成真實的數據幀長度
 
        long frameLength = getUnadjustedFrameLength(in, actualLengthFieldOffset, lengthFieldLength, byteOrder);
 
 
 
 
 
        // 如果讀取到的frameLength 小于 0, 說明此數據有問題, 拋出異常
 
        if (frameLength < 0) {
 
            failOnNegativeLengthField(in, frameLength, lengthFieldEndOffset);
 
        }
 
 
 
        // 調整frameLength長度  frameLength = frameLength + lengthAdjustment + lengthFieldEndOffset
 
        // frameLength + lengthAdjustment 表示真實數據的長度
 
        // 即這里的frameLength 就是整個數據的長度(包括真實數據).
 
        frameLength += lengthAdjustment + lengthFieldEndOffset;
 
 
 
        // 如果frameLength < lengthFieldEndOffset  那只能說明在上面的計算過程中, frameLength + lengthAdjustment < 0 了.
 
        // frameLength + lengthAdjustment 表示真實數據的長度, 數據的長度怎么會小于0呢   因此拋異常.
 
        if (frameLength < lengthFieldEndOffset) {
 
            failOnFrameLengthLessThanLengthFieldEndOffset(in, frameLength, lengthFieldEndOffset);
 
        }
 
 
 
        // 如果整個數據的長度大于設定的最大值. 那么認為這是無效數據, 需要跳過這個無效數據
 
        if (frameLength > maxFrameLength) {
 
            // 跳過一個frameLength長度的數據
 
            exceededFrameLength(in, frameLength);
 
            return null;
 
        }
 
 
 
        // never overflows because it's less than maxFrameLength
 
        int frameLengthInt = (int) frameLength;
 
        // 表示目前可讀的數據還不夠一個幀, 那么直接返回
 
        if (in.readableBytes() < frameLengthInt) {
 
            return null;
 
        }
 
 
 
        // 比如一個即將要讀取的幀長度=10,  可是initialBytesToStrip = 12, 跳過的字節(jié)比要讀取的字節(jié)還大,  讀取的字節(jié)還不夠跳過的, 有問題   直接拋異常
 
        if (initialBytesToStrip > frameLengthInt) {
 
            failOnFrameLengthLessThanInitialBytesToStrip(in, frameLength, initialBytesToStrip);
 
        }
 
        in.skipBytes(initialBytesToStrip);
 
 
 
        // extract frame
 
        // 讀取實際有意義的業(yè)務數據
 
        int readerIndex = in.readerIndex();
 
        int actualFrameLength = frameLengthInt - initialBytesToStrip;
 
        ByteBuf frame = extractFrame(ctx, in, readerIndex, actualFrameLength);
 
        in.readerIndex(readerIndex + actualFrameLength);
 
        return frame;
 
    }

總結

以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關文章

  • Java字符串中刪除指定子字符串的方法簡介

    Java字符串中刪除指定子字符串的方法簡介

    這篇文章主要介紹了Java字符串中刪除指定子字符串的方法,是Java入門學習中的基礎知識,需要的朋友可以參考下
    2015-11-11
  • Java面向對象之多態(tài)

    Java面向對象之多態(tài)

    這篇文章主要介紹了Java面向對象之多態(tài),文章以什么是多態(tài)、多態(tài)的實現條件、多態(tài)的訪問特點、多態(tài)的優(yōu)點和缺點的相關資料展開文章內容,需要的小伙伴可以參考一下
    2021-10-10
  • java基本教程之常用的實現多線程的兩種方式 java多線程教程

    java基本教程之常用的實現多線程的兩種方式 java多線程教程

    下面開始學習“常用的實現多線程的2種方式”:Thread 和 Runnable。之所以說是常用的,是因為通過還可以通過java.util.concurrent包中的線程池來實現多線程
    2014-01-01
  • Spring MVC+MyBatis+MySQL實現分頁功能實例

    Spring MVC+MyBatis+MySQL實現分頁功能實例

    分頁功能是我們日常開發(fā)中經常會遇到的,下面這篇文章主要給大家介紹了Spring MVC+MyBatis+MySQL實現分頁功能的相關資料,文中介紹的非常詳細,對大家具有一定的參考學習價值,需要的朋友們下面來一起看看吧。
    2017-06-06
  • 淺析spring定時器的使用

    淺析spring定時器的使用

    這篇文章主要介紹了淺析spring定時器的使用,幫助大家更好的理解和學習spring框架,感興趣的朋友可以了解下
    2020-10-10
  • mybatisplus如何實現排序

    mybatisplus如何實現排序

    這篇文章主要介紹了mybatisplus如何實現排序問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-02-02
  • SpringBoot詳解自定義Stater的應用

    SpringBoot詳解自定義Stater的應用

    Springboot的出現極大的簡化了開發(fā)人員的配置,而這之中的一大利器便是springboot的starter,starter是springboot的核心組成部分,springboot官方同時也為開發(fā)人員封裝了各種各樣方便好用的starter模塊
    2022-07-07
  • JPA延遲加載no Session報錯解決分析

    JPA延遲加載no Session報錯解決分析

    這篇文章主要為大家介紹了JPA延遲加載no Session報錯解決分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-09-09
  • Java入門交換數組中兩個元素的位置

    Java入門交換數組中兩個元素的位置

    在Java中,交換數組中的兩個元素是基本的數組操作,下面我們將詳細介紹如何實現這一操作,以及在實際應用中這種技術的重要性,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-09-09
  • Java獲取工程路徑方法詳解

    Java獲取工程路徑方法詳解

    這篇文章主要介紹了Java獲取工程路徑方法詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-03-03

最新評論

金寨县| 嘉善县| 南江县| 泸溪县| 呼图壁县| 建始县| 横山县| 息烽县| 惠来县| 东城区| 聂荣县| 明溪县| 迭部县| 乌兰浩特市| 三穗县| 尚志市| 梅河口市| 咸阳市| 彩票| 乌拉特后旗| 保靖县| 哈巴河县| 泌阳县| 阆中市| 长治市| 如皋市| 阜平县| 天峻县| 酒泉市| 镇康县| 巴楚县| 益阳市| 同江市| 紫阳县| 三穗县| 乐至县| 宝鸡市| 绿春县| 钟祥市| 武川县| 稻城县|