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

Netty中解碼器的作用及實(shí)現(xiàn)詳解

 更新時間:2023年12月21日 10:20:32   作者:Colins~  
這篇文章主要介紹了Netty中解碼器的作用及實(shí)現(xiàn)詳解,本章我們只需要讓客戶端發(fā)送消息的時候循環(huán)發(fā)送100次,服務(wù)端不變,看看服務(wù)端是不是接收到了100條消息,需要的朋友可以參考下

拆包和沾包

是典型的拆包和沾包問題,俗話說就是兩端通信,一端發(fā)送一端接收,接收的那一端怎么知道是否已經(jīng)完整的接收了數(shù)據(jù)?

假設(shè)服務(wù)端連續(xù)發(fā)送了兩條消息:hello world! / hello client!

由于客戶端不知道怎么才算一條消息,怎么才算兩條消息,所以讀取會有以下幾種情況:

1.分兩次讀取消息,第一次是hello world!,第二次是hello client!   這是正常情況

2.一次就讀取完成,hello world!hello client!                  這種情況就叫沾包

3.分兩次讀取消息,第一次是hello ,第二次是world!hello client!   這第一次讀取就是拆包,第二次就是沾包

總之就是讀取到的信息不完整就是拆包,讀取到的信息有額外多的信息就是沾包

演示

我們接著上一章的代碼來演示,我們只需要讓客戶端發(fā)送消息的時候循環(huán)發(fā)送100次,服務(wù)端不變,看看服務(wù)端是不是接收到了100條消息

NettyClientTestHandler

在這里插入圖片描述

結(jié)果如下:

在這里插入圖片描述

這明顯就不對吧

解決方案

要怎么解決這種問題呢?

  1. 消息定長,每條消息都固定長度,不夠則補(bǔ)空格
  2. 添加分隔符,等于是為每條消息都增加一個結(jié)束標(biāo)識
  3. 將消息分為消息頭和消息體,消息頭固定長度,里面包含整條消息的長度或者消息體的長度
  4. 更復(fù)雜的協(xié)議約定

下面我們通過Netty中幾種內(nèi)置的解碼器來解決這種問題:

  • LineBasedFrameDecoder:行分隔符解碼器(結(jié)尾根據(jù) “\n” 作為結(jié)束標(biāo)識)
  • DelimiterBasedFrameDecoder:自定義分割器解碼器,結(jié)尾根據(jù)什么作為結(jié)束標(biāo)識可以自定義
  • FixedLengthFrameDecoder:固定長度解碼器,發(fā)送的消息需要定長
  • LengthFieldBasedFrameDecoder:基于長度的自定義解碼器,比較靈活

注意:所有編解碼在Netty中都是數(shù)據(jù)處理管道當(dāng)中的一個數(shù)據(jù)處理器而已

LineBasedFrameDecoder

這個是采用行分隔符來解決,所以我們需要改兩個地方

1.發(fā)送消息的時候,消息結(jié)尾要加上行分隔符(接著上面的例子來)

在這里插入圖片描述

2.服務(wù)端接收消息,需要在管道內(nèi)加入解碼器

LineBasedFrameDecoder:傳入的參數(shù)是消息最大長度,發(fā)送消息的大小必須小于設(shè)置值

在這里插入圖片描述

結(jié)果如下:

在這里插入圖片描述

DelimiterBasedFrameDecoder

這個跟上面一樣,只不過分隔符我們可以自定義

1.發(fā)送消息的時候,消息結(jié)尾要加上分隔符(這里我們定義分隔符是 “$$”)

在這里插入圖片描述

2.服務(wù)端接收消息,需要在管道內(nèi)加入解碼器

在這里插入圖片描述

結(jié)果如下:

在這里插入圖片描述

FixedLengthFrameDecoder

會按照設(shè)置的固定字節(jié)大小來切割消息

1.這里我們正常的發(fā)送消息就好了

在這里插入圖片描述

2.服務(wù)端接收消息,需要在管道內(nèi)加入解碼器

在這里插入圖片描述

結(jié)果如下:

在這里插入圖片描述

LengthFieldBasedFrameDecoder

這個是需要重點(diǎn)介紹一下的,上面三個解碼器明顯的看到不夠靈活,太過于死板,我們看看這個怎么用

源代碼構(gòu)造如下

public LengthFieldBasedFrameDecoder(int maxFrameLength, int lengthFieldOffset, int lengthFieldLength, int lengthAdjustment, int initialBytesToStrip) {
    this(maxFrameLength, lengthFieldOffset, lengthFieldLength, lengthAdjustment, initialBytesToStrip, true);
}

參數(shù)含義:

  • maxFrameLength:最大幀長度。也就是可以接收的數(shù)據(jù)的最大長度。如果超過,此次數(shù)據(jù)會被丟棄
  • lengthFieldOffset:長度域偏移量。存儲數(shù)據(jù)長度的一個偏移量
  • lengthFieldLength:長度域字節(jié)數(shù)。存儲數(shù)據(jù)長度的一個大小
  • lengthAdjustment:數(shù)據(jù)長度修正。因?yàn)殚L度既可以代表data的長度,也可以是整個消息的長度
  • initialBytesToStrip:跳過的字節(jié)數(shù)??梢赃x擇舍棄一部分?jǐn)?shù)據(jù)

這參數(shù)前三個可以比較好理解,后兩個是干嘛的?沒關(guān)系我們一步一步來,后兩個先不用

假設(shè)我們要發(fā)送一個消息,結(jié)構(gòu)為:消息頭+數(shù)據(jù)長度+數(shù)據(jù)(Hello Server)

在這里插入圖片描述

看看我們要怎么設(shè)置:

整體消息長度:20個字節(jié)、數(shù)據(jù)data長度:12字節(jié)
首先我們要找到長度域,所以要往右讀取4個字節(jié):      lengthFieldOffset設(shè)置為4
然后需要讀取數(shù)據(jù)的長度,所以需要再往右讀4個字節(jié):   lengthFieldLength設(shè)置為4
之后會根據(jù)上面讀取到的數(shù)據(jù)長度再往后讀取數(shù)據(jù):
假設(shè)這里數(shù)據(jù)長度是12,則會繼續(xù)往后讀取12個字節(jié)
至此數(shù)據(jù)就全讀取完了(lengthAdjustment和initialBytesToStrip都設(shè)置成0的情況下)

下面我們演示一下:

NettyClientTestHandler

客戶端發(fā)送消息,結(jié)構(gòu)為:消息頭+數(shù)據(jù)長度+數(shù)據(jù)

@Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        String data= "Hello Server";
        ByteBuf buffer = Unpooled.buffer();
        // 請求頭 4字節(jié)
        buffer.writeInt(666);
        // 數(shù)據(jù)長度 4字節(jié)
        buffer.writeInt(data.getBytes().length);
        // 然后寫入數(shù)據(jù)
        buffer.writeBytes(Unpooled.copiedBuffer(data, CharsetUtil.UTF_8));
        // 寫入并發(fā)送 完整的數(shù)據(jù)為  666+12+Hello Server
        ctx.writeAndFlush(buffer);
        SocketAddress socketAddress = ctx.channel().remoteAddress();
        log.info(socketAddress + " 已連接");
    }

NettyServerTestHandler

服務(wù)端按照結(jié)構(gòu)解析消息

@Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        // 和NIO一樣有緩沖區(qū) ByteBuf就是對ByteBuffer做了一層封裝
        ByteBuf msg1 = (ByteBuf) msg;
        // 讀取請求頭
        log.info("請求頭:" + msg1.readInt());
        // 讀取長度
        int i = msg1.readInt();
        log.info("數(shù)據(jù)長度:" + i);
        // 讀取數(shù)據(jù)
        log.info("客戶端信息:" + msg1.readBytes(i).toString(CharsetUtil.UTF_8));
    }

服務(wù)端編碼設(shè)置

在這里插入圖片描述

結(jié)果如下:

在這里插入圖片描述

initialBytesToStrip參數(shù)的作用

像上面這樣沾包拆包的問題解決了,但是有一個點(diǎn)很麻煩,就是每次讀取消息都需要一步一步的拆解消息,能不能把消息體前面無用的數(shù)據(jù)直接舍棄掉,只保留有用的數(shù)據(jù)部分呢?

在這里插入圖片描述

可以!initialBytesToStrip參數(shù)就是可以在數(shù)據(jù)讀取完后,可以選擇跳過多少字節(jié)(你可以理解為舍棄,這樣簡單點(diǎn)),就像上面這個例子,我不需要請求頭和數(shù)據(jù)長度的8個字節(jié),我只需要后面的數(shù)據(jù)體,所以我可以將initialBytesToStrip設(shè)置成8

改動兩個地方

在這里插入圖片描述

服務(wù)端就不需要再拆解了,直接讀取

在這里插入圖片描述

lengthAdjustment參數(shù)的作用

上面我們知道了最后會根據(jù)長度域里面的數(shù)據(jù)來決定再往后讀取多少個字節(jié),這里我們設(shè)置的數(shù)據(jù)長度是12,所以剛剛好往后讀取了12個字節(jié),讀取完成了,要是我設(shè)置的數(shù)據(jù)長度不是12呢?那往后讀取多少個字節(jié),這個是不是需要修正?

所以lengthAdjustment的作用就是來修正最終往后讀取多少個字節(jié)

假設(shè)我設(shè)置的數(shù)據(jù)長度是20,代表了整個消息體的長度,但是我數(shù)據(jù)卻只有12個字節(jié),這往后讀20個字節(jié)無疑是錯的,所以我們需要修正,怎么修正? 減8唄,對吧

所以最終往后讀取多少個字節(jié)=數(shù)據(jù)長度+lengthAdjustment像上面為例,我們就需要設(shè)置成-8

總結(jié)

這章主要介紹了解碼器的作用,沾包拆包的問題,但是還是存在一些問題:

每次發(fā)送消息都要寫特定格式,是不是太麻煩了?(自定義編碼器)現(xiàn)在傳輸都是簡單的字符串,實(shí)際都是實(shí)體類對象,這咋搞?(序列化和反序列化)

之后再介紹怎么自定義協(xié)議解決這些問題

到此這篇關(guān)于Netty中解碼器的作用及實(shí)現(xiàn)詳解的文章就介紹到這了,更多相關(guān)Netty解碼器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • idea 創(chuàng)建properties配置文件的步驟

    idea 創(chuàng)建properties配置文件的步驟

    這篇文章主要介紹了idea 創(chuàng)建properties配置文件的步驟,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-01-01
  • spring boot整合netty的實(shí)現(xiàn)方法

    spring boot整合netty的實(shí)現(xiàn)方法

    這篇文章主要介紹了spring boot整合netty的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08
  • 入門JDK集合之HashMap解析

    入門JDK集合之HashMap解析

    HashMap---基于哈希表的 Map 接口的實(shí)現(xiàn)。此實(shí)現(xiàn)提供所有可選的映射操作,并允許使用 null 值和 null 鍵。(除了非同步和允許使用 null 之外,HashMap 類與 Hashtable 大致相同
    2021-06-06
  • java實(shí)現(xiàn)單源最短路徑

    java實(shí)現(xiàn)單源最短路徑

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)單源最短路徑,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-01-01
  • 通過實(shí)例解析spring bean之間的關(guān)系

    通過實(shí)例解析spring bean之間的關(guān)系

    這篇文章主要介紹了通過實(shí)例解析spring bean之間的關(guān)系,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-01-01
  • Mybatis中返回主鍵值方式

    Mybatis中返回主鍵值方式

    這篇文章主要介紹了Mybatis中返回主鍵值方式,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • Spring?Security?核心過濾器鏈講解

    Spring?Security?核心過濾器鏈講解

    這篇文章主要介紹了Spring?Security?核心過濾器鏈,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • java compareTo和compare方法比較詳解

    java compareTo和compare方法比較詳解

    這篇文章主要介紹了java compareTo和compare方法比較詳解,本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-09-09
  • SpringBoot如何使用@Cacheable進(jìn)行緩存與取值

    SpringBoot如何使用@Cacheable進(jìn)行緩存與取值

    這篇文章主要介紹了SpringBoot如何使用@Cacheable進(jìn)行緩存與取值,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • windows下jar包開機(jī)自動重啟的步驟

    windows下jar包開機(jī)自動重啟的步驟

    這篇文章主要給大家介紹了關(guān)于windows下jar包開機(jī)自動重啟的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11

最新評論