欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Nett分布式分隔符解碼器邏輯源碼剖析

 更新時(shí)間:2022年03月29日 11:09:23   作者:向南是個(gè)萬(wàn)人迷  
這篇文章主要為大家介紹了Nett分布式分隔符解碼器邏輯源碼剖析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

前文傳送門(mén):Netty分布式行解碼器邏輯源碼解析

分隔符解碼器

基于分隔符解碼器DelimiterBasedFrameDecoder, 是按照指定分隔符進(jìn)行解碼的解碼器, 通過(guò)分隔符, 可以將二進(jìn)制流拆分成完整的數(shù)據(jù)包

同樣繼承了ByteToMessageDecoder并重寫(xiě)了decode方法

我們看其中的一個(gè)構(gòu)造方法

public DelimiterBasedFrameDecoder(int maxFrameLength, ByteBuf... delimiters) {
    this(maxFrameLength, true, delimiters);
}

這里參數(shù)maxFrameLength代表最大長(zhǎng)度, delimiters是個(gè)可變參數(shù), 可以說(shuō)可以支持多個(gè)分隔符進(jìn)行解碼

我們進(jìn)入decode方法:

protected final void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
    Object decoded = decode(ctx, in);
    if (decoded != null) {
        out.add(decoded);
    }
}

這里同樣調(diào)用了其重載的decode方法并將解析好的數(shù)據(jù)添加到集合list中, 其父類(lèi)就可以遍歷out, 并將內(nèi)容傳播

我們跟到重載decode方法中

protected Object decode(ChannelHandlerContext ctx, ByteBuf buffer) throws Exception {
    //行處理器(1)
    if (lineBasedDecoder != null) { 
        return lineBasedDecoder.decode(ctx, buffer);
    }
    int minFrameLength = Integer.MAX_VALUE;
    ByteBuf minDelim = null; 
    //找到最小長(zhǎng)度的分隔符(2)
    for (ByteBuf delim: delimiters) {
        //每個(gè)分隔符分隔的數(shù)據(jù)包長(zhǎng)度
        int frameLength = indexOf(buffer, delim);
        if (frameLength >= 0 && frameLength < minFrameLength) {
            minFrameLength = frameLength;
            minDelim = delim;
        }
    }
    //解碼(3)
    //已經(jīng)找到分隔符
    if (minDelim != null) {
        int minDelimLength = minDelim.capacity();
        ByteBuf frame;
        //當(dāng)前分隔符否處于丟棄模式
        if (discardingTooLongFrame) { 
            //首先設(shè)置為非丟棄模式
            discardingTooLongFrame = false;
            //丟棄
            buffer.skipBytes(minFrameLength + minDelimLength);

            int tooLongFrameLength = this.tooLongFrameLength;
            this.tooLongFrameLength = 0;
            if (!failFast) {
                fail(tooLongFrameLength);
            }
            return null;
        }
        //處于非丟棄模式
        //當(dāng)前找到的數(shù)據(jù)包, 大于允許的數(shù)據(jù)包
        if (minFrameLength > maxFrameLength) {
            //當(dāng)前數(shù)據(jù)包+最小分隔符長(zhǎng)度 全部丟棄
            buffer.skipBytes(minFrameLength + minDelimLength);
            //傳遞異常事件
            fail(minFrameLength);
            return null;
        }
        //如果是正常的長(zhǎng)度
        //解析出來(lái)的數(shù)據(jù)包是否忽略分隔符
        if (stripDelimiter) {
            //如果不包含分隔符
            //截取
            frame = buffer.readRetainedSlice(minFrameLength);
            //跳過(guò)分隔符
            buffer.skipBytes(minDelimLength);
        } else {
            //截取包含分隔符的長(zhǎng)度
            frame = buffer.readRetainedSlice(minFrameLength + minDelimLength);
        }
        return frame;
    } else {
        //如果沒(méi)有找到分隔符
        //非丟棄模式
        if (!discardingTooLongFrame) {
            //可讀字節(jié)大于允許的解析出來(lái)的長(zhǎng)度
            if (buffer.readableBytes() > maxFrameLength) {
                //將這個(gè)長(zhǎng)度記錄下
                tooLongFrameLength = buffer.readableBytes();
                //跳過(guò)這段長(zhǎng)度
                buffer.skipBytes(buffer.readableBytes());
                //標(biāo)記當(dāng)前處于丟棄狀態(tài)
                discardingTooLongFrame = true;
                if (failFast) {
                    fail(tooLongFrameLength);
                }
            }
        } else {
            tooLongFrameLength += buffer.readableBytes();
            buffer.skipBytes(buffer.readableBytes());
        }
        return null;
    }
}

這里的方法也比較長(zhǎng), 這里也通過(guò)拆分進(jìn)行剖析

(1). 行處理器

(2). 找到最小長(zhǎng)度分隔符

(3). 解碼

首先看第一步行處理器:

if (lineBasedDecoder != null) { 
    return lineBasedDecoder.decode(ctx, buffer);
}

這里首先判斷成員變量lineBasedDecoder是否為空, 如果不為空則直接調(diào)用lineBasedDecoder的decode的方法進(jìn)行解碼, lineBasedDecoder實(shí)際上就是上一小節(jié)剖析的LineBasedFrameDecoder解碼器

這個(gè)成員變量, 會(huì)在分隔符是\n和\r\n的時(shí)候進(jìn)行初始化

我們看初始化該屬性的構(gòu)造方法

public DelimiterBasedFrameDecoder(
        int maxFrameLength, boolean stripDelimiter, boolean failFast, ByteBuf... delimiters) {
    //代碼省略
    //如果是基于行的分隔
    if (isLineBased(delimiters) && !isSubclass()) {
        //初始化行處理器
        lineBasedDecoder = new LineBasedFrameDecoder(maxFrameLength, stripDelimiter, failFast);
        this.delimiters = null;
    } else {
        //代碼省略
    }
    //代碼省略
}

這里isLineBased(delimiters)會(huì)判斷是否是基于行的分隔, 跟到isLineBased方法中:

private static boolean isLineBased(final ByteBuf[] delimiters) {
    //分隔符長(zhǎng)度不為2
    if (delimiters.length != 2) {
        return false;
    }
    //拿到第一個(gè)分隔符
    ByteBuf a = delimiters[0];
    //拿到第二個(gè)分隔符
    ByteBuf b = delimiters[1];
    if (a.capacity() < b.capacity()) {
        a = delimiters[1];
        b = delimiters[0];
    }
    //確保a是/r/n分隔符, 確保b是/n分隔符
    return a.capacity() == 2 && b.capacity() == 1
            && a.getByte(0) == '\r' && a.getByte(1) == '\n'
            && b.getByte(0) == '\n';
}

首先判斷長(zhǎng)度等于2, 直接返回false

然后拿到第一個(gè)分隔符a和第二個(gè)分隔符b, 然后判斷a的第一個(gè)分隔符是不是\r, a的第二個(gè)分隔符是不是\n, b的第一個(gè)分隔符是不是\n, 如果都為true, 則條件成立

我們回到decode方法中, 看步驟2, 找到最小長(zhǎng)度的分隔符:

這里最小長(zhǎng)度的分隔符, 意思就是從讀指針開(kāi)始, 找到最近的分隔符

for (ByteBuf delim: delimiters) {
    //每個(gè)分隔符分隔的數(shù)據(jù)包長(zhǎng)度
    int frameLength = indexOf(buffer, delim);
    if (frameLength >= 0 && frameLength < minFrameLength) {
        minFrameLength = frameLength;
        minDelim = delim;
    }
}

這里會(huì)遍歷所有的分隔符, 然后找到每個(gè)分隔符到讀指針到數(shù)據(jù)包長(zhǎng)度

然后通過(guò)if判斷, 找到長(zhǎng)度最小的數(shù)據(jù)包的長(zhǎng)度, 然后保存當(dāng)前數(shù)據(jù)包的的分隔符, 如下圖:

6-4-1

這里假設(shè)A和B同為分隔符, A分隔符到讀指針的長(zhǎng)度小于B分隔符到讀指針的長(zhǎng)度, 這里會(huì)找到最小的分隔符A, 分隔符的最小長(zhǎng)度, 就readIndex到A的長(zhǎng)度

我們繼續(xù)看第3步, 解碼:

 if (minDelim != null) 表示已經(jīng)找到最小長(zhǎng)度分隔符, 我們繼續(xù)看if塊中的邏輯:

int minDelimLength = minDelim.capacity();
ByteBuf frame; 
if (discardingTooLongFrame) { 
    discardingTooLongFrame = false; 
    buffer.skipBytes(minFrameLength + minDelimLength); 
    int tooLongFrameLength = this.tooLongFrameLength;
    this.tooLongFrameLength = 0;
    if (!failFast) {
        fail(tooLongFrameLength);
    }
    return null;
} 
if (minFrameLength > maxFrameLength) { 
    buffer.skipBytes(minFrameLength + minDelimLength); 
    fail(minFrameLength);
    return null;
} 
if (stripDelimiter) { 
    frame = buffer.readRetainedSlice(minFrameLength); 
    buffer.skipBytes(minDelimLength);
} else { 
    frame = buffer.readRetainedSlice(minFrameLength + minDelimLength);
}
return frame;

 if (discardingTooLongFrame) 表示當(dāng)前是否處于非丟棄模式, 如果是丟棄模式, 則進(jìn)入if塊

因?yàn)榈谝粋€(gè)不是丟棄模式, 所以這里先分析if塊后面的邏輯

 if (minFrameLength > maxFrameLength) 這里是判斷當(dāng)前找到的數(shù)據(jù)包長(zhǎng)度大于最大長(zhǎng)度, 這里的最大長(zhǎng)度使我們創(chuàng)建解碼器的時(shí)候設(shè)置的, 如果超過(guò)了最大長(zhǎng)度, 就通過(guò) buffer.skipBytes(minFrameLength + minDelimLength) 方式, 跳過(guò)數(shù)據(jù)包+分隔符的長(zhǎng)度, 也就是將這部分?jǐn)?shù)據(jù)進(jìn)行完全丟棄

繼續(xù)往下看, 如果長(zhǎng)度不大最大允許長(zhǎng)度, 則通過(guò) if (stripDelimiter) 判斷解析的出來(lái)的數(shù)據(jù)包是否包含分隔符, 如果不包含分隔符, 則截取數(shù)據(jù)包的長(zhǎng)度之后, 跳過(guò)分隔符

我們?cè)倩仡^看 if (discardingTooLongFrame) 中的if塊中的邏輯, 也就是丟棄模式:

首先將discardingTooLongFrame設(shè)置為false, 標(biāo)記非丟棄模式

然后通過(guò) buffer.skipBytes(minFrameLength + minDelimLength) 將數(shù)據(jù)包+分隔符長(zhǎng)度的字節(jié)數(shù)跳過(guò), 也就是進(jìn)行丟棄, 之后再進(jìn)行拋出異常

分析完成了找到分隔符之后的丟棄模式非丟棄模式的邏輯處理, 我們?cè)诜治鰶](méi)找到分隔符的邏輯處理, 也就是 if (minDelim != null) 中的else塊:

if (!discardingTooLongFrame) { 
    if (buffer.readableBytes() > maxFrameLength) { 
        tooLongFrameLength = buffer.readableBytes();
        buffer.skipBytes(buffer.readableBytes());
        discardingTooLongFrame = true;
        if (failFast) {
            fail(tooLongFrameLength);
        }
    }
} else {
    tooLongFrameLength += buffer.readableBytes();
    buffer.skipBytes(buffer.readableBytes());
}
return null;

首先通過(guò) if (!discardingTooLongFrame) 判斷是否為非丟棄模式, 如果是, 則進(jìn)入if塊:

在if塊中, 首先通過(guò) if (buffer.readableBytes() > maxFrameLength) 判斷當(dāng)前可讀字節(jié)數(shù)是否大于最大允許的長(zhǎng)度, 如果大于最大允許的長(zhǎng)度, 則將可讀字節(jié)數(shù)設(shè)置到tooLongFrameLength的屬性中, 代表丟棄的字節(jié)數(shù)

然后通過(guò) buffer.skipBytes(buffer.readableBytes()) 將累計(jì)器中所有的可讀字節(jié)進(jìn)行丟棄

最后將discardingTooLongFrame設(shè)置為true, 也就是丟棄模式, 之后拋出異常

如果 if (!discardingTooLongFrame) 為false, 也就是當(dāng)前處于丟棄模式, 則追加tooLongFrameLength也就是丟棄的字節(jié)數(shù)的長(zhǎng)度, 并通過(guò) buffer.skipBytes(buffer.readableBytes()) 將所有的字節(jié)繼續(xù)進(jìn)行丟棄

以上就是分隔符解碼器的相關(guān)邏輯

章節(jié)總結(jié)

本章介紹了抽象解碼器ByteToMessageDecoder, 和其他幾個(gè)實(shí)現(xiàn)了ByteToMessageDecoder類(lèi)的解碼器, 這個(gè)幾個(gè)解碼器邏輯都比較簡(jiǎn)單, 同學(xué)們可以根據(jù)其中的思想剖析其他的比較復(fù)雜的解碼器, 或者根據(jù)其規(guī)則實(shí)現(xiàn)自己的自定義解碼器

更多關(guān)于Nett分布式分隔符解碼器的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 三種SpringBoot中實(shí)現(xiàn)異步調(diào)用的方法總結(jié)

    三種SpringBoot中實(shí)現(xiàn)異步調(diào)用的方法總結(jié)

    Spring Boot 提供了多種方式來(lái)實(shí)現(xiàn)異步任務(wù),這篇文章主要為大家介紹了常用的三種實(shí)現(xiàn)方式,文中的示例代碼講解詳細(xì),需要的可以參考一下
    2023-05-05
  • Netty的心跳檢測(cè)解析

    Netty的心跳檢測(cè)解析

    這篇文章主要介紹了Netty的心跳檢測(cè)解析,客戶(hù)端的心跳檢測(cè)對(duì)于任何長(zhǎng)連接的應(yīng)用來(lái)說(shuō),都是一個(gè)非?;A(chǔ)的功能,要理解心跳的重要性,首先需要從網(wǎng)絡(luò)連接假死的現(xiàn)象說(shuō)起,需要的朋友可以參考下
    2023-12-12
  • 淺談Java對(duì)象禁止使用基本類(lèi)型

    淺談Java對(duì)象禁止使用基本類(lèi)型

    本文主要介紹了淺談Java對(duì)象禁止使用基本類(lèi)型,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-02-02
  • JustAuth整合第三方登錄組件樣例

    JustAuth整合第三方登錄組件樣例

    這篇文章主要為大家介紹了JustAuth整合第三方登錄組件樣例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-07-07
  • Spring詳細(xì)講解事務(wù)失效的場(chǎng)景

    Spring詳細(xì)講解事務(wù)失效的場(chǎng)景

    實(shí)際項(xiàng)目開(kāi)發(fā)中,如果涉及到多張表操作時(shí),為了保證業(yè)務(wù)數(shù)據(jù)的一致性,大家一般都會(huì)采用事務(wù)機(jī)制,好多小伙伴可能只是簡(jiǎn)單了解一下,遇到事務(wù)失效的情況,便會(huì)無(wú)從下手,下面這篇文章主要給大家介紹了關(guān)于Spring事務(wù)失效場(chǎng)景的相關(guān)資料,需要的朋友可以參考下
    2022-07-07
  • Java常見(jiàn)啟動(dòng)命令-jar、-server和-cp詳細(xì)比較

    Java常見(jiàn)啟動(dòng)命令-jar、-server和-cp詳細(xì)比較

    這篇文章主要給大家介紹了關(guān)于Java常見(jiàn)啟動(dòng)命令-jar、-server和-cp詳細(xì)比較的相關(guān)資料,該文總結(jié)了常歸的jar包的啟動(dòng)方式,并分析各種啟動(dòng)方式的區(qū)別,需要的朋友可以參考下
    2023-07-07
  • SpringBoot2.2.X用Freemarker出現(xiàn)404的解決

    SpringBoot2.2.X用Freemarker出現(xiàn)404的解決

    這篇文章主要介紹了SpringBoot2.2.X用Freemarker出現(xiàn)404的解決,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-02-02
  • JavaFX程序初次運(yùn)行創(chuàng)建數(shù)據(jù)庫(kù)并執(zhí)行建表SQL詳解

    JavaFX程序初次運(yùn)行創(chuàng)建數(shù)據(jù)庫(kù)并執(zhí)行建表SQL詳解

    這篇文章主要介紹了JavaFX程序初次運(yùn)行創(chuàng)建數(shù)據(jù)庫(kù)并執(zhí)行建表SQL詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-08-08
  • Java使用Jsoup解析html網(wǎng)頁(yè)的實(shí)現(xiàn)步驟

    Java使用Jsoup解析html網(wǎng)頁(yè)的實(shí)現(xiàn)步驟

    Jsoup是一個(gè)用于解析HTML文檔的Java庫(kù),本文主要介紹了Java使用Jsoup解析html網(wǎng)頁(yè)的實(shí)現(xiàn)步驟,可以提取文本、鏈接、圖片等,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-02-02
  • Java Code Cache滿(mǎn)導(dǎo)致應(yīng)用性能降低問(wèn)題解決

    Java Code Cache滿(mǎn)導(dǎo)致應(yīng)用性能降低問(wèn)題解決

    這篇文章主要介紹了Java Code Cache滿(mǎn)導(dǎo)致應(yīng)用性能降低問(wèn)題解決,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-08-08

最新評(píng)論