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

詳解netty中的frame解碼器

 更新時(shí)間:2022年04月28日 14:16:19   作者:flydean程序那些事  
netty為我們提供了一些合適的frame解碼器,通過(guò)使用這些frame解碼器可以有效的簡(jiǎn)化我們的工作,這篇文章主要介紹了netty中的frame解碼器,需要的朋友可以參考下

簡(jiǎn)介

netty中的數(shù)據(jù)是通過(guò)ByteBuf來(lái)進(jìn)行傳輸?shù)?,一個(gè)ByteBuf中可能包含多個(gè)有意義的數(shù)據(jù),這些數(shù)據(jù)可以被稱(chēng)作frame,也就是說(shuō)一個(gè)ByteBuf中可以包含多個(gè)Frame。

對(duì)于消息的接收方來(lái)說(shuō),接收到了ByteBuf,還需要從ByteBuf中解析出有用而數(shù)據(jù),那就需要將ByteBuf中的frame進(jìn)行拆分和解析。

一般來(lái)說(shuō)不同的frame之間會(huì)有有些特定的分隔符,我們可以通過(guò)這些分隔符來(lái)區(qū)分frame,從而實(shí)現(xiàn)對(duì)數(shù)據(jù)的解析。

netty為我們提供了一些合適的frame解碼器,通過(guò)使用這些frame解碼器可以有效的簡(jiǎn)化我們的工作。下圖是netty中常見(jiàn)的幾個(gè)frame解碼器:

接下來(lái)我們來(lái)詳細(xì)介紹一下上面幾個(gè)frame解碼器的使用。

LineBasedFrameDecoder

LineBasedFrameDecoder從名字上看就是按行來(lái)進(jìn)行frame的區(qū)分。根據(jù)操作系統(tǒng)的不同,換行可以有兩種換行符,分別是 “\n” 和 “\r\n” 。

LineBasedFrameDecoder的基本原理就是從ByteBuf中讀取對(duì)應(yīng)的字符來(lái)和"\n" 跟 “\r\n”,可以了可以準(zhǔn)確的進(jìn)行字符的比較,這些frameDecoder對(duì)字符的編碼也會(huì)有一定的要求,一般來(lái)說(shuō)是需要UTF-8編碼。因?yàn)樵谶@樣的編碼中,“\n"和”\r"是以一個(gè)byte出現(xiàn)的,并且不會(huì)用在其他的組合編碼中,所以用"\n"和"\r"來(lái)進(jìn)行判斷是非常安全的。

LineBasedFrameDecoder中有幾個(gè)比較重要的屬性,一個(gè)是maxLength的屬性,用來(lái)檢測(cè)接收到的消息長(zhǎng)度,如果超出了長(zhǎng)度限制,則會(huì)拋出TooLongFrameException異常。

還有一個(gè)stripDelimiter屬性,用來(lái)判斷是否需要將delimiter過(guò)濾掉。

還有一個(gè)是failFast,如果該值為true,那么不管frame是否讀取完成,只要frame的長(zhǎng)度超出了maxFrameLength,就會(huì)拋出TooLongFrameException。如果該值為false,那么TooLongFrameException會(huì)在整個(gè)frame完全讀取之后再拋出。

LineBasedFrameDecoder的核心邏輯是先找到行的分隔符的位置,然后根據(jù)這個(gè)位置讀取到對(duì)應(yīng)的frame信息,這里來(lái)看一下找到行分隔符的findEndOfLine方法:

private int findEndOfLine(final ByteBuf buffer) {
        int totalLength = buffer.readableBytes();
        int i = buffer.forEachByte(buffer.readerIndex() + offset, totalLength - offset, ByteProcessor.FIND_LF);
        if (i >= 0) {
            offset = 0;
            if (i > 0 && buffer.getByte(i - 1) == '\r') {
                i--;
            }
        } else {
            offset = totalLength;
        }
        return i;
    }

這里使用了一個(gè)ByteBuf的forEachByte對(duì)ByteBuf進(jìn)行遍歷。我們要找的字符是:ByteProcessor.FIND_LF。

最后LineBasedFrameDecoder解碼之后的對(duì)象還是一個(gè)ByteBuf。

DelimiterBasedFrameDecoder

上面講的LineBasedFrameDecoder只對(duì)行分隔符有效,如果我們的frame是以其他的分隔符來(lái)分割的話LineBasedFrameDecoder就用不了了,所以netty提供了一個(gè)更加通用的DelimiterBasedFrameDecoder,這個(gè)frameDecoder可以自定義delimiter:

public class DelimiterBasedFrameDecoder extends ByteToMessageDecoder {
        public DelimiterBasedFrameDecoder(int maxFrameLength, ByteBuf delimiter) {
        this(maxFrameLength, true, delimiter);
    }

傳入的delimiter是一個(gè)ByteBuf,所以delimiter可能不止一個(gè)字符。

為了解決這個(gè)問(wèn)題在DelimiterBasedFrameDecoder中定義了一個(gè)ByteBuf的數(shù)組:

 private final ByteBuf[] delimiters;
    delimiters= delimiter.readableBytes();

這個(gè)delimiters是通過(guò)調(diào)用delimiter的readableBytes得到的。

DelimiterBasedFrameDecoder的邏輯和LineBasedFrameDecoder差不多,都是通過(guò)對(duì)比bufer中的字符來(lái)對(duì)bufer中的數(shù)據(jù)進(jìn)行截取,但是DelimiterBasedFrameDecoder可以接受多個(gè)delimiters,所以它的用處會(huì)根據(jù)廣泛。

FixedLengthFrameDecoder

除了進(jìn)行ByteBuf中字符比較來(lái)進(jìn)行frame拆分之外,還有一些其他常見(jiàn)的frame拆分的方法,比如根據(jù)特定的長(zhǎng)度來(lái)區(qū)分,netty提供了一種這樣的decoder叫做FixedLengthFrameDecoder。

public class FixedLengthFrameDecoder extends ByteToMessageDecoder 

FixedLengthFrameDecoder也是繼承自ByteToMessageDecoder,它的定義很簡(jiǎn)單,可以傳入一個(gè)frame的長(zhǎng)度:

public FixedLengthFrameDecoder(int frameLength) {
        checkPositive(frameLength, "frameLength");
        this.frameLength = frameLength;
    }

然后調(diào)用ByteBuf的readRetainedSlice方法來(lái)讀取固定長(zhǎng)度的數(shù)據(jù):

in.readRetainedSlice(frameLength)

最后將讀取到的數(shù)據(jù)返回。

LengthFieldBasedFrameDecoder

還有一些frame中包含了特定的長(zhǎng)度字段,這個(gè)長(zhǎng)度字段表示ByteBuf中有多少可讀的數(shù)據(jù),這樣的frame叫做LengthFieldBasedFrame。

netty中也提供了一個(gè)對(duì)應(yīng)的處理decoder:

public class LengthFieldBasedFrameDecoder extends ByteToMessageDecoder 

讀取的邏輯很簡(jiǎn)單,首先讀取長(zhǎng)度,然后再根據(jù)長(zhǎng)度再讀取數(shù)據(jù)。為了實(shí)現(xiàn)這個(gè)邏輯,LengthFieldBasedFrameDecoder提供了4個(gè)字段,分別是 lengthFieldOffset,lengthFieldLength,lengthAdjustment和initialBytesToStrip。

lengthFieldOffset指定了長(zhǎng)度字段的開(kāi)始位置,lengthFieldLength定義的是長(zhǎng)度字段的長(zhǎng)度,lengthAdjustment是對(duì)lengthFieldLength進(jìn)行調(diào)整,initialBytesToStrip表示是否需要去掉長(zhǎng)度字段。

聽(tīng)起來(lái)好像不太好理解,我們舉幾個(gè)例子,首先是最簡(jiǎn)單的:

BEFORE DECODE (14 bytes)         AFTER DECODE (14 bytes)
   +--------+----------------+      +--------+----------------+
   | Length | Actual Content |----->| Length | Actual Content |
   | 0x000C | "HELLO, WORLD" |      | 0x000C | "HELLO, WORLD" |
   +--------+----------------+      +--------+----------------+

要編碼的消息有個(gè)長(zhǎng)度字段,長(zhǎng)度字段后面就是真實(shí)的數(shù)據(jù),0x000C是一個(gè)十六進(jìn)制,表示的數(shù)據(jù)是12,也就是"HELLO, WORLD" 中字符串的長(zhǎng)度。

這里4個(gè)屬性的值是:

lengthFieldOffset   = 0
   lengthFieldLength   = 2
   lengthAdjustment    = 0
   initialBytesToStrip = 0 

表示的是長(zhǎng)度字段從0開(kāi)始,并且長(zhǎng)度字段占有兩個(gè)字節(jié),長(zhǎng)度不需要調(diào)整,也不需要對(duì)字段進(jìn)行調(diào)整。

再來(lái)看一個(gè)比較復(fù)雜的例子,在這個(gè)例子中4個(gè)屬性值如下:

 lengthFieldOffset   = 1  
   lengthFieldLength   = 2
   lengthAdjustment    = 1  
   initialBytesToStrip = 3  

對(duì)應(yīng)的編碼數(shù)據(jù)如下所示:

BEFORE DECODE (16 bytes)                       AFTER DECODE (13 bytes)
   +------+--------+------+----------------+      +------+----------------+
   | HDR1 | Length | HDR2 | Actual Content |----->| HDR2 | Actual Content |
   | 0xCA | 0x000C | 0xFE | "HELLO, WORLD" |      | 0xFE | "HELLO, WORLD" |
   +------+--------+------+----------------+      +------+----------------+

上面的例子中長(zhǎng)度字段是從第1個(gè)字節(jié)開(kāi)始的(第0個(gè)字節(jié)是HDR1),長(zhǎng)度字段占有2個(gè)字節(jié),長(zhǎng)度再調(diào)整一個(gè)字節(jié),最終數(shù)據(jù)的開(kāi)始位置就是1+2+1=4,然后再截取前3個(gè)字節(jié)的數(shù)據(jù),得到了最后的結(jié)果。

總結(jié)

netty提供的這幾個(gè)基于字符集的frame decoder基本上能夠滿足我們?nèi)粘5墓ぷ餍枨罅恕.?dāng)然,如果你傳輸?shù)氖且恍└訌?fù)雜的對(duì)象,那么可以考慮自定義編碼和解碼器。自定義的邏輯步驟和上面我們講解的保持一致就行了。

到此這篇關(guān)于netty中的frame解碼器的文章就介紹到這了,更多相關(guān)netty解碼器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringMVC使用MultipartResolver實(shí)現(xiàn)文件上傳

    SpringMVC使用MultipartResolver實(shí)現(xiàn)文件上傳

    MultipartResolver 用于處理文件上傳,當(dāng)收到請(qǐng)求時(shí) DispatcherServlet 的 checkMultipart() 方法會(huì)調(diào)用 MultipartResolver 的 isMultipart() 方法判斷請(qǐng)求中是否包含文件
    2023-02-02
  • Mybatis自動(dòng)創(chuàng)建表和更新表結(jié)構(gòu)

    Mybatis自動(dòng)創(chuàng)建表和更新表結(jié)構(gòu)

    這篇文章主要介紹了Mybatis自動(dòng)創(chuàng)建表和更新表結(jié)構(gòu)的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2016-06-06
  • JAVA面試題String產(chǎn)生了幾個(gè)對(duì)象

    JAVA面試題String產(chǎn)生了幾個(gè)對(duì)象

    這篇文章主要介紹了JAVA面試題 String s = new String("xyz");產(chǎn)生了幾個(gè)對(duì)象?,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-07-07
  • Jmeter線程組傳參原理解析

    Jmeter線程組傳參原理解析

    這篇文章主要介紹了jmeter線程組傳參原理解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-02-02
  • MyBatis Mapper接受參數(shù)的四種方式代碼解析

    MyBatis Mapper接受參數(shù)的四種方式代碼解析

    這篇文章主要介紹了MyBatis Mapper接受參數(shù)的四種方式代碼解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-02-02
  • Mybatis-Plus根據(jù)自定義注解實(shí)現(xiàn)自動(dòng)加解密的示例代碼

    Mybatis-Plus根據(jù)自定義注解實(shí)現(xiàn)自動(dòng)加解密的示例代碼

    我們把數(shù)據(jù)存到數(shù)據(jù)庫(kù)的時(shí)候,有些敏感字段是需要加密的,從數(shù)據(jù)庫(kù)查出來(lái)再進(jìn)行解密,如果我們使用的是Mybatis框架,那就跟著一起探索下如何使用框架的攔截器功能實(shí)現(xiàn)自動(dòng)加解密吧,需要的朋友可以參考下
    2024-06-06
  • SpringMVC+Mysql實(shí)例詳解(附demo)

    SpringMVC+Mysql實(shí)例詳解(附demo)

    本篇文章主要介紹了SpringMVC+Mysql實(shí)例詳解(附demo),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。
    2016-12-12
  • springboot導(dǎo)入多個(gè)配置文件的方法實(shí)踐

    springboot導(dǎo)入多個(gè)配置文件的方法實(shí)踐

    Spring Boot 2.4.x引入了新的配置導(dǎo)入方式,通過(guò)spring.config.import屬性可以靈活地導(dǎo)入多種類(lèi)型的配置文件,本文就來(lái)介紹一下,感興趣的可以了解一下
    2024-11-11
  • Java深度復(fù)制功能與用法實(shí)例分析

    Java深度復(fù)制功能與用法實(shí)例分析

    這篇文章主要介紹了Java深度復(fù)制功能與用法,簡(jiǎn)單講述了深度復(fù)制的概念、功能并結(jié)合實(shí)例形式分析了java實(shí)現(xiàn)深度復(fù)制的具體操作技巧,需要的朋友可以參考下
    2018-01-01
  • idea每次新打開(kāi)的項(xiàng)目窗口maven都要重新設(shè)置問(wèn)題

    idea每次新打開(kāi)的項(xiàng)目窗口maven都要重新設(shè)置問(wèn)題

    這篇文章主要介紹了idea每次新打開(kāi)的項(xiàng)目窗口maven都要重新設(shè)置問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-11-11

最新評(píng)論

永州市| 外汇| 孝义市| 盐山县| 盱眙县| 安宁市| 永德县| 台州市| 西青区| 四平市| 义乌市| 化州市| 怀安县| 澳门| 青海省| 岢岚县| 息烽县| 郯城县| 略阳县| 海城市| 富裕县| 霍林郭勒市| 准格尔旗| 临城县| 临猗县| 和田市| 南川市| 黑龙江省| 东阳市| 岑溪市| 清水县| 呼伦贝尔市| 丹巴县| 托克托县| 石屏县| 广南县| 蕲春县| 锦屏县| 河曲县| 怀仁县| 南安市|