91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

netty中的frame解碼器怎么用

發布時間:2022-04-28 16:46:31 來源:億速云 閱讀:141 作者:iii 欄目:開發技術

這篇文章主要介紹“netty中的frame解碼器怎么用”的相關知識,小編通過實際案例向大家展示操作過程,操作方法簡單快捷,實用性強,希望這篇“netty中的frame解碼器怎么用”文章能幫助大家解決問題。

簡介

netty中的數據是通過ByteBuf來進行傳輸的,一個ByteBuf中可能包含多個有意義的數據,這些數據可以被稱作frame,也就是說一個ByteBuf中可以包含多個Frame。

對于消息的接收方來說,接收到了ByteBuf,還需要從ByteBuf中解析出有用而數據,那就需要將ByteBuf中的frame進行拆分和解析。

一般來說不同的frame之間會有有些特定的分隔符,我們可以通過這些分隔符來區分frame,從而實現對數據的解析。

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

netty中的frame解碼器怎么用

接下來我們來詳細介紹一下上面幾個frame解碼器的使用。

LineBasedFrameDecoder

LineBasedFrameDecoder從名字上看就是按行來進行frame的區分。根據操作系統的不同,換行可以有兩種換行符,分別是 “\n” 和 “\r\n” 。

LineBasedFrameDecoder的基本原理就是從ByteBuf中讀取對應的字符來和"\n" 跟 “\r\n”,可以了可以準確的進行字符的比較,這些frameDecoder對字符的編碼也會有一定的要求,一般來說是需要UTF-8編碼。因為在這樣的編碼中,“\n"和”\r"是以一個byte出現的,并且不會用在其他的組合編碼中,所以用"\n"和"\r"來進行判斷是非常安全的。

LineBasedFrameDecoder中有幾個比較重要的屬性,一個是maxLength的屬性,用來檢測接收到的消息長度,如果超出了長度限制,則會拋出TooLongFrameException異常。

還有一個stripDelimiter屬性,用來判斷是否需要將delimiter過濾掉。

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

LineBasedFrameDecoder的核心邏輯是先找到行的分隔符的位置,然后根據這個位置讀取到對應的frame信息,這里來看一下找到行分隔符的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;
    }

這里使用了一個ByteBuf的forEachByte對ByteBuf進行遍歷。我們要找的字符是:ByteProcessor.FIND_LF。

最后LineBasedFrameDecoder解碼之后的對象還是一個ByteBuf。

DelimiterBasedFrameDecoder

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

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

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

為了解決這個問題在DelimiterBasedFrameDecoder中定義了一個ByteBuf的數組:

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

這個delimiters是通過調用delimiter的readableBytes得到的。

DelimiterBasedFrameDecoder的邏輯和LineBasedFrameDecoder差不多,都是通過對比bufer中的字符來對bufer中的數據進行截取,但是DelimiterBasedFrameDecoder可以接受多個delimiters,所以它的用處會根據廣泛。

FixedLengthFrameDecoder

除了進行ByteBuf中字符比較來進行frame拆分之外,還有一些其他常見的frame拆分的方法,比如根據特定的長度來區分,netty提供了一種這樣的decoder叫做FixedLengthFrameDecoder。

public class FixedLengthFrameDecoder extends ByteToMessageDecoder

FixedLengthFrameDecoder也是繼承自ByteToMessageDecoder,它的定義很簡單,可以傳入一個frame的長度:

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

然后調用ByteBuf的readRetainedSlice方法來讀取固定長度的數據:

in.readRetainedSlice(frameLength)

最后將讀取到的數據返回。

LengthFieldBasedFrameDecoder

還有一些frame中包含了特定的長度字段,這個長度字段表示ByteBuf中有多少可讀的數據,這樣的frame叫做LengthFieldBasedFrame。

netty中也提供了一個對應的處理decoder:

public class LengthFieldBasedFrameDecoder extends ByteToMessageDecoder

讀取的邏輯很簡單,首先讀取長度,然后再根據長度再讀取數據。為了實現這個邏輯,LengthFieldBasedFrameDecoder提供了4個字段,分別是 lengthFieldOffset,lengthFieldLength,lengthAdjustment和initialBytesToStrip。

lengthFieldOffset指定了長度字段的開始位置,lengthFieldLength定義的是長度字段的長度,lengthAdjustment是對lengthFieldLength進行調整,initialBytesToStrip表示是否需要去掉長度字段。

聽起來好像不太好理解,我們舉幾個例子,首先是最簡單的:

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

要編碼的消息有個長度字段,長度字段后面就是真實的數據,0x000C是一個十六進制,表示的數據是12,也就是"HELLO, WORLD" 中字符串的長度。

這里4個屬性的值是:

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

表示的是長度字段從0開始,并且長度字段占有兩個字節,長度不需要調整,也不需要對字段進行調整。

再來看一個比較復雜的例子,在這個例子中4個屬性值如下:

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

對應的編碼數據如下所示:

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

上面的例子中長度字段是從第1個字節開始的(第0個字節是HDR1),長度字段占有2個字節,長度再調整一個字節,最終數據的開始位置就是1+2+1=4,然后再截取前3個字節的數據,得到了最后的結果。

關于“netty中的frame解碼器怎么用”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識,可以關注億速云行業資訊頻道,小編每天都會為大家更新不同的知識點。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

皋兰县| 弥渡县| 仁寿县| 馆陶县| 温宿县| 桦川县| 万山特区| 桐柏县| 科技| 湖口县| 偃师市| 仁怀市| 平凉市| 台北市| 古浪县| 巴楚县| 波密县| 杂多县| 西安市| 永胜县| 龙江县| 佛学| 布尔津县| 乐都县| 武胜县| 崇仁县| 兴隆县| 伊吾县| 进贤县| 海兴县| 漯河市| 德昌县| 泰兴市| 堆龙德庆县| 历史| 文成县| 拉萨市| 沁水县| 平远县| 娄烦县| 本溪市|