Netty入门(十)解码分隔符和基于长度的协议

Stella981
• 阅读 491

我们需要区分不同帧的首尾,通常需要在结尾设定特定分隔符或者在首部添加长度字段,分别称为分隔符协议和基于长度的协议,本节讲解 Netty 如何解码这些协议。

一、分隔符协议

Netty 附带的解码器可以很容易的提取一些序列分隔:

Netty入门(十)解码分隔符和基于长度的协议

下面显示了使用 “\r\n”分隔符的处理:

Netty入门(十)解码分隔符和基于长度的协议

下面为 LineBaseFrameDecoder 的简单实现:

 1 public class CmdHandlerInitializer extends ChannelInitializer<Channel> {
 2 
 3     @Override
 4     protected void initChannel(Channel ch) throws Exception {
 5         ChannelPipeline pipeline = ch.pipeline();
 6         // 添加解码器,
 7         pipeline.addLast(new CmdDecoder(65 * 1024));
 8         pipeline.addLast(new CmdHandler());
 9     }
10 
11     public static final class Cmd {
12         private final ByteBuf name;    // 名字
13         private final ByteBuf args;    // 参数
14         
15         public Cmd(ByteBuf name, ByteBuf args) {
16             this.name = name;
17             this.args = args;
18         }
19         
20         public ByteBuf name() {
21             return name;
22         }
23         
24         public ByteBuf args() {
25             return args;
26         }
27     }
28     
29     /**
30      * 根据分隔符将消息解码成Cmd对象传给下一个处理器
31      */
32     public static final class CmdDecoder extends LineBasedFrameDecoder {
33 
34         public CmdDecoder(int maxLength) {
35             super(maxLength);
36         }
37         
38         @Override
39         protected Object decode(ChannelHandlerContext ctx, ByteBuf buffer) throws Exception {
40             // 通过结束分隔符从 ByteBuf 提取帧
41             ByteBuf frame = (ByteBuf)super.decode(ctx, buffer);
42             if(frame == null)
43                 return null;
44             int index = frame.indexOf(frame.readerIndex(), frame.writerIndex(), (byte)' ');
45             // 提取 Cmd 对象
46             return new Cmd(frame.slice(frame.readerIndex(), index), 
47                     frame.slice(index+1, frame.writerIndex()));
48         }
49     }
50     
51     public static final class CmdHandler extends SimpleChannelInboundHandler<Cmd> {
52 
53         @Override
54         protected void channelRead0(ChannelHandlerContext ctx, Cmd msg) throws Exception {
55             // 处理 Cmd 信息
56         }
57         
58     }
59 }

  上面的例子主要实现了利用换行符‘\n’分隔帧,然后将每行数据解码成一个 Cmd 实例。

二、基于长度的协议 

  基于长度的协议在帧头定义了一个帧编码的长度,而不是在结束位置用一个特殊的分隔符来标记。Netty 提供了两种编码器,用于处理这种类型的协议,如下:

Netty入门(十)解码分隔符和基于长度的协议

  FixedLengthFrameDecoder 的操作是提取固定长度每帧 8 字节,如下图所示:

Netty入门(十)解码分隔符和基于长度的协议

但大部分时候,我们会把帧的大小编码在头部,这种情况可以使用 LengthFieldBaseFrameDecoder,它会提取帧的长度并根据长度读取帧的数据部分,如下:

Netty入门(十)解码分隔符和基于长度的协议

下面是 LengthFieldBaseFrameDecoder 的一个简单应用:

 1 /**
 2  * 基于长度的协议
 3  * LengthFieldBasedFrameDecoder
 4  */
 5 public class LineBasedHandlerInitializer extends ChannelInitializer<Channel> {
 6 
 7     @Override
 8     protected void initChannel(Channel ch) throws Exception {
 9         ChannelPipeline pipeline = ch.pipeline();
10         // 用于提取基于帧编码长度8个字节的帧
11         pipeline.addLast(new LengthFieldBasedFrameDecoder(65*1024, 0, 8));
12         pipeline.addLast(new FrameHandler());
13     }
14     
15     public static final class FrameHandler extends SimpleChannelInboundHandler<ByteBuf> {
16 
17         @Override
18         protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
19             // TODO 数据处理
20         }
21         
22     }
23 
24 }

  上面的例子主要实现了提取帧首部 8 字节的长度,然后提取数据部分进行处理。

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Easter79 Easter79
2年前
sql注入
反引号是个比较特别的字符,下面记录下怎么利用0x00SQL注入反引号可利用在分隔符及注释作用,不过使用范围只于表名、数据库名、字段名、起别名这些场景,下面具体说下1)表名payload:select\from\users\whereuser\_id1limit0,1;!(https://o
Stella981 Stella981
2年前
Netty和Tomcat的区别、性能对比
一、Netty和Tomcat有什么区别? Netty和Tomcat最大的区别就在于通信协议,Tomcat是基于Http协议的,他的实质是一个基于http协议的web容器,但是Netty不一样,他能通过编程自定义各种协议,因为netty能够通过codec自己来编码/解码字节流,完成类似redis访问的功能,这就是netty和tomcat最大的不同。有人
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Stella981 Stella981
2年前
JavaScript常用函数
1\.字符串长度截取functioncutstr(str,len){vartemp,icount0,patrn/^\x00\xff/,strre"";for(vari
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这