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

Netty中的DelimiterBasedFrameDecoder使用方法詳解

 更新時(shí)間:2023年12月15日 10:41:58   作者:mzjnumber1  
這篇文章主要介紹了Netty中的DelimiterBasedFrameDecoder使用方法詳解,DelimiterBasedFrameDecoder與LineBasedFrameDecoder類似,只不過(guò)更加通用,允許我們指定任意特殊字符作為分隔符,我們還可以同時(shí)指定多個(gè)分隔符,需要的朋友可以參考下

1 DelimiterBasedFrameDecoder介紹

前面介紹了LineBasedFrameDecoder,其以換行符\n或者\(yùn)r\n作為依據(jù),遇到\n或者\(yùn)r\n都認(rèn)為是一條完整的消息。

而DelimiterBasedFrameDecoder與LineBasedFrameDecoder類似,只不過(guò)更加通用,允許我們指定任意特殊字符作為分隔符。我們還可以同時(shí)指定多個(gè)分隔符,如果在請(qǐng)求中發(fā)的確有多個(gè)分隔符,將會(huì)選擇內(nèi)容最短的一個(gè)分隔符作為依據(jù)。 例如:

   +--------------+
   | ABC\nDEF\r\n |
   +--------------+

如果我們指定分隔符為\n,那么將會(huì)解碼出來(lái)2個(gè)消息

   +-----+-----+
   | ABC | DEF |
   +-----+-----+

如果我們指定\r\n作為分隔符,那么只會(huì)解碼出來(lái)一條消息

   +----------+
   | ABC\nDEF |
   +----------+

DelimiterBasedFrameDecoder提供了多個(gè)構(gòu)造方法,最終調(diào)用的都是以下構(gòu)造方法:

public DelimiterBasedFrameDecoder(
            int maxFrameLength, boolean stripDelimiter, boolean failFast, ByteBuf... delimiters)

其中:

maxLength:

表示一行最大的長(zhǎng)度,如果超過(guò)這個(gè)長(zhǎng)度依然沒(méi)有檢測(cè)到\n或者\(yùn)r\n,將會(huì)拋出TooLongFrameException

failFast:

與maxLength聯(lián)合使用,表示超過(guò)maxLength后,拋出TooLongFrameException的時(shí)機(jī)。如果為true,則超出maxLength后立即拋出TooLongFrameException,不繼續(xù)進(jìn)行解碼;如果為false,則等到完整的消息被解碼后,再拋出TooLongFrameException異常。

stripDelimiter:

解碼后的消息是否去除分隔符。

delimiters:

分隔符。我們需要先將分割符,寫(xiě)入到ByteBuf中,然后當(dāng)做參數(shù)傳入。

需要注意的是,netty并沒(méi)有提供一個(gè)DelimiterBasedFrameDecoder對(duì)應(yīng)的編碼器實(shí)現(xiàn)(筆者沒(méi)有找到),因此在發(fā)送端需要自行編碼,添加分隔符。

2 Base64編解碼

對(duì)于以特殊字符作為報(bào)文分割條件的協(xié)議的解碼器,如:LineBasedFrameDecoder、DelimiterBasedFrameDecoder。

都存在一個(gè)典型的問(wèn)題,如果發(fā)送數(shù)據(jù)當(dāng)中本身就包含了分隔符,怎么辦?如:我們要發(fā)送的內(nèi)容為:

hello1\nhello2\nhello3\n

我們需要把這個(gè)內(nèi)容整體當(dāng)做一個(gè)有效報(bào)文來(lái)處理,而不是拆分成hello1、hello2、hello3。一些同學(xué)可能想到那可以換其他的特殊字符,但是如果內(nèi)容中又包含你想指定的其他特殊字符怎么辦呢?

因此我們通常需要發(fā)送的內(nèi)容進(jìn)行base64編碼,base64中總共只包含了64個(gè)字符。

我們可以指定這64個(gè)字符之外的其他字符作為特殊分割字符;而接收端對(duì)應(yīng)的進(jìn)行base64解碼,得到對(duì)應(yīng)的原始的二進(jìn)制流,然后進(jìn)行處理。Netty提供了Base64Encoder/Base64Decoder來(lái)幫我們處理這個(gè)問(wèn)題。需要注意的是,只需要對(duì)內(nèi)容進(jìn)行base64編碼,分隔符不需要編碼。

3 DelimiterBasedFrameDecoder結(jié)合Base64編解碼案例

Server端:DelimiterBasedFrameDecoderServer

public class DelimiterBasedFrameDecoderServer {
   public static void main(String[] args) throws Exception {
      EventLoopGroup bossGroup = new NioEventLoopGroup(); // (1)
      EventLoopGroup workerGroup = new NioEventLoopGroup();
      try {
         ServerBootstrap b = new ServerBootstrap(); // (2)
         b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class) // (3)
               .childHandler(new ChannelInitializer<SocketChannel>() { // (4)
                  @Override
                  public void initChannel(SocketChannel ch) throws Exception {
                     ByteBuf delemiter= Unpooled.buffer();
                     delemiter.writeBytes("&".getBytes());
                    //先使用DelimiterBasedFrameDecoder解碼,以&作為分割符
                    ch.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, true, true,delemiter));
                    //之后使用Base64Decoder對(duì)數(shù)據(jù)進(jìn)行解碼,得到報(bào)文的原始的二進(jìn)制流
                    ch.pipeline().addLast(new Base64Decoder());
                    //對(duì)請(qǐng)求報(bào)文進(jìn)行處理
                     ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {
                        @Override
                        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                           if (msg instanceof ByteBuf) {
                              ByteBuf packet = (ByteBuf) msg;
                              System.out.println(
                                    new Date().toLocaleString() + ":" + packet.toString(Charset.defaultCharset()));
                           }
                        }
                     });
                  }
               });
         // Bind and start to accept incoming connections.
         ChannelFuture f = b.bind(8080).sync(); // (7)
         System.out.println("DelimiterBasedFrameDecoderServer Started on 8080...");
         f.channel().closeFuture().sync();
      } finally {
         workerGroup.shutdownGracefully();
         bossGroup.shutdownGracefully();
      }
   }
}

Server接受到的數(shù)據(jù),首先我們要去除分隔符,然后才能進(jìn)行base64解碼。因此首選我們添加了DelimiterBasedFrameDecoder根據(jù)&處理粘包辦包問(wèn)題,之后使用Base64Decoder進(jìn)行解碼,最后通過(guò)一個(gè)自定義ChannelInboundHandler打印請(qǐng)求的數(shù)據(jù)。client端:DelimiterBasedFrameDecoderClient

public class DelimiterBasedFrameDecoderClient {
   public static void main(String[] args) throws Exception {
      EventLoopGroup workerGroup = new NioEventLoopGroup();
      try {
         Bootstrap b = new Bootstrap(); // (1)
         b.group(workerGroup); // (2)
         b.channel(NioSocketChannel.class); // (3)
         b.option(ChannelOption.SO_KEEPALIVE, true); // (4)
         b.handler(new ChannelInitializer<SocketChannel>() {
            @Override
            public void initChannel(SocketChannel ch) throws Exception {
               ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {
                   //在于server建立連接后,即發(fā)送請(qǐng)求報(bào)文
                  public void channelActive(ChannelHandlerContext ctx) {
                     //先對(duì)要發(fā)送的原始內(nèi)容進(jìn)行base64編碼
                     ByteBuf content = Base64.encode(Unpooled.buffer().writeBytes("hello&tianshouzhi&".getBytes
                           ()));
                     //之后添加分隔符
                     ByteBuf req = Unpooled.copiedBuffer(content);
                     req.writeBytes("&".getBytes());
                     ctx.writeAndFlush(req);
                        }
               });
            }
         });
         // Start the client.
         ChannelFuture f = b.connect("127.0.0.1",8080).sync(); // (5)
         // Wait until the connection is closed.
         f.channel().closeFuture().sync();
      } finally {
         workerGroup.shutdownGracefully();
      }
   }
}

在編寫(xiě)client端代碼時(shí)我們先對(duì)原始內(nèi)容進(jìn)行base64編碼,然后添加分割符之后進(jìn)行輸出。

需要注意,雖然Netty提供了Base64Encoder進(jìn)行編碼,這里并沒(méi)有直接使用,如果直接使用Base64Encoder,那么會(huì)對(duì)我們輸出的所有內(nèi)容進(jìn)行編碼,意味著分隔符也會(huì)被編碼,這顯然不符合我們的預(yù)期,所以這里直接使用了Netty提供了Base64工具類來(lái)處理。

如果一定要使用Base64Encoder,那么代碼需要進(jìn)行相應(yīng)的修改,自定義的ChannelInboundHandler只輸出原始內(nèi)容,之后通過(guò)Base64Encoder進(jìn)行編碼,然后需要額外再定義一個(gè)ChannelOutboundHandler添加分隔符,如:

ch.pipeline().addLast(new ChannelOutboundHandlerAdapter() {
   @Override
   public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
      if(msg instanceof ByteBuf){
         ((ByteBuf) msg).writeBytes("&".getBytes());
      }
   }
});
ch.pipeline().addLast(new Base64Encoder());
ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {
    //在于server建立連接后,即發(fā)送請(qǐng)求報(bào)文
   public void channelActive(ChannelHandlerContext ctx) {
      ByteBuf req = Unpooled.buffer().writeBytes("hello&tianshouzhi&".getBytes());
      ctx.writeAndFlush(req);
                   }
});

上述兩種方案效果是等價(jià)的。

當(dāng)我們先后啟動(dòng)server和client后,會(huì)看到server端控制臺(tái)輸出:

DelimiterBasedFrameDecoderServer Started on 8080...
2018-9-8 13:56:32:hello&tianshouzhi&

說(shuō)明經(jīng)過(guò)base64編碼后,我們的請(qǐng)求中可以包含分隔符作為內(nèi)容。

如果我們將base64編解碼相關(guān)邏輯去掉,你將會(huì)看到的輸出是:

DelimiterBasedFrameDecoderServer Started on 8080...
2018-9-8 14:13:31:hello
2018-9-8 14:13:31:tianshouzhi

也就是說(shuō),原始內(nèi)容也被誤分割了,解碼失敗,讀者可以自行驗(yàn)證。

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

相關(guān)文章

  • SpringBoot 創(chuàng)建對(duì)象常見(jiàn)的幾種方式小結(jié)

    SpringBoot 創(chuàng)建對(duì)象常見(jiàn)的幾種方式小結(jié)

    Spring Boot中創(chuàng)建對(duì)象的幾種常見(jiàn)方式包括使用@Component、@Service、@Repository或@Controller注解,本文就來(lái)詳細(xì)的介紹一下,感興趣的可以了解一下
    2024-11-11
  • Java等待喚醒機(jī)制原理實(shí)例解析

    Java等待喚醒機(jī)制原理實(shí)例解析

    這篇文章主要介紹了Java等待喚醒機(jī)制原理實(shí)例解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-01-01
  • Java程序開(kāi)發(fā)中abstract 和 interface的區(qū)別詳解

    Java程序開(kāi)發(fā)中abstract 和 interface的區(qū)別詳解

    abstract class和interface在Java語(yǔ)言中都是用來(lái)進(jìn)行抽象類。但是兩者有什么區(qū)別呢,接下來(lái)小編給大家?guī)?lái)了abstract 和 interface的區(qū)別詳解,感興趣的朋友一起學(xué)習(xí)吧
    2016-06-06
  • 詳解MyBatis特性之動(dòng)態(tài)SQL

    詳解MyBatis特性之動(dòng)態(tài)SQL

    動(dòng)態(tài) SQL 是 MyBatis 的強(qiáng)大特性之一,這篇文章我們將結(jié)合動(dòng)態(tài)SQL完成更加復(fù)雜的 SQL 操作,文章通過(guò)代碼示例給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下
    2024-01-01
  • Java開(kāi)發(fā)如何把數(shù)據(jù)庫(kù)里的未付款訂單改成已付款

    Java開(kāi)發(fā)如何把數(shù)據(jù)庫(kù)里的未付款訂單改成已付款

    這篇文章主要介紹了Java開(kāi)發(fā)如何把數(shù)據(jù)庫(kù)里的未付款訂單改成已付款,先介紹MD5算法,簡(jiǎn)單的來(lái)說(shuō),MD5能把任意大小、長(zhǎng)度的數(shù)據(jù)轉(zhuǎn)換成固定長(zhǎng)度的一串字符,實(shí)現(xiàn)思路非常簡(jiǎn)單需要的朋友可以參考下
    2022-11-11
  • 詳解Spring 中 Bean 的生命周期

    詳解Spring 中 Bean 的生命周期

    這篇文章主要介紹了Spring 中 Bean 的生命周期的相關(guān)資料,幫助大家更好的理解和使用spring框架,感興趣的朋友可以了解下。
    2021-01-01
  • Springboot中useGeneratedKeys用法小結(jié)

    Springboot中useGeneratedKeys用法小結(jié)

    本文主要介紹了Springboot中useGeneratedKeys用法小結(jié),useGeneratedKeys?是 MyBatis 框架中的一個(gè)參數(shù),用于指定是否允許 JDBC 支持自動(dòng)生成主鍵,感興趣的可以了解一下
    2024-09-09
  • Java中序列化和反序列化的完整講解

    Java中序列化和反序列化的完整講解

    序列化是將對(duì)象轉(zhuǎn)換成二進(jìn)制字節(jié)流的過(guò)程;反序列化是從二進(jìn)制字節(jié)流中恢復(fù)對(duì)象的過(guò)程。文中將為大家詳細(xì)講講二者的原理與實(shí)現(xiàn),需要的可以參考一下
    2022-11-11
  • 三分鐘帶你了解SpringBoot真正的啟動(dòng)引導(dǎo)類

    三分鐘帶你了解SpringBoot真正的啟動(dòng)引導(dǎo)類

    這篇文章主要介紹了三分鐘帶你了解SpringBoot真正的啟動(dòng)引導(dǎo)類,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • 解決使用@ManyToMany查詢數(shù)據(jù)時(shí)的死循環(huán)問(wèn)題

    解決使用@ManyToMany查詢數(shù)據(jù)時(shí)的死循環(huán)問(wèn)題

    這篇文章主要介紹了解決使用@ManyToMany查詢數(shù)據(jù)時(shí)的死循環(huán)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12

最新評(píng)論

惠安县| 孟连| 南和县| 余江县| 孙吴县| 醴陵市| 枣庄市| 高尔夫| 万安县| 江都市| 禹城市| 长丰县| 无锡市| 安陆市| 文安县| 泰和县| 洮南市| 江达县| 博客| 拉孜县| 汉阴县| 林芝县| 宁陕县| 甘泉县| 库伦旗| 交城县| 察隅县| 岳阳县| 石台县| 金华市| 宁强县| 茂名市| 无极县| 东宁县| 顺义区| 德安县| 三江| 黄石市| 新民市| 保山市| 宁陕县|