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

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

一、分隔符协议

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

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

下面为 LineBaseFrameDecoder 的简单实现:

1 1 public class CmdHandlerInitializer extends ChannelInitializer<Channel> { 2 2 3 3 @Override 4 4 protected void initChannel(Channel ch) throws Exception { 5 5 ChannelPipeline pipeline = ch.pipeline(); 6 6 // 添加解码器, 7 7 pipeline.addLast(new CmdDecoder(65 * 1024)); 8 8 pipeline.addLast(new CmdHandler()); 9 9 } 1010 1111 public static final class Cmd { 1212 private final ByteBuf name; // 名字 1313 private final ByteBuf args; // 参数 1414 1515 public Cmd(ByteBuf name, ByteBuf args) { 1616 this.name = name; 1717 this.args = args; 1818 } 1919 2020 public ByteBuf name() { 2121 return name; 2222 } 2323 2424 public ByteBuf args() { 2525 return args; 2626 } 2727 } 2828 2929 /** 3030 * 根据分隔符将消息解码成Cmd对象传给下一个处理器 3131 */ 3232 public static final class CmdDecoder extends LineBasedFrameDecoder { 3333 3434 public CmdDecoder(int maxLength) { 3535 super(maxLength); 3636 } 3737 3838 @Override 3939 protected Object decode(ChannelHandlerContext ctx, ByteBuf buffer) throws Exception { 4040 // 通过结束分隔符从 ByteBuf 提取帧 4141 ByteBuf frame = (ByteBuf)super.decode(ctx, buffer); 4242 if(frame == null) 4343 return null; 4444 int index = frame.indexOf(frame.readerIndex(), frame.writerIndex(), (byte)' '); 4545 // 提取 Cmd 对象 4646 return new Cmd(frame.slice(frame.readerIndex(), index), 4747 frame.slice(index+1, frame.writerIndex())); 4848 } 4949 } 5050 5151 public static final class CmdHandler extends SimpleChannelInboundHandler<Cmd> { 5252 5353 @Override 5454 protected void channelRead0(ChannelHandlerContext ctx, Cmd msg) throws Exception { 5555 // 处理 Cmd 信息 5656 } 5757 5858 } 5959 }

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

二、基于长度的协议 

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

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

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

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

1 1 /** 2 2 * 基于长度的协议 3 3 * LengthFieldBasedFrameDecoder 4 4 */ 5 5 public class LineBasedHandlerInitializer extends ChannelInitializer<Channel> { 6 6 7 7 @Override 8 8 protected void initChannel(Channel ch) throws Exception { 9 9 ChannelPipeline pipeline = ch.pipeline(); 1010 // 用于提取基于帧编码长度8个字节的帧 1111 pipeline.addLast(new LengthFieldBasedFrameDecoder(65*1024, 0, 8)); 1212 pipeline.addLast(new FrameHandler()); 1313 } 1414 1515 public static final class FrameHandler extends SimpleChannelInboundHandler<ByteBuf> { 1616 1717 @Override 1818 protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception { 1919 // TODO 数据处理 2020 } 2121 2222 } 2323 2424 }

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

点赞
收藏

评论区

加载中...

相关推荐

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

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

sql注入

反引号是个比较特别的字符,下面记录下怎么利用0x00SQL注入反引号可利用在分隔符及注释作用,不过使用范围只于表名、数据库名、字段名、起别名这些场景,下面具体说下1)表名payload:select\from\users\whereuser\_id1limit0,1;!(https://o