使用netty的ReplayingDecoder解决长度变化的复杂数据格式的拆包粘包

ReplayingDecoder

简介

ReplayingDecoder用于解决通讯时粘包和拆包的问题以及用于分步解析数据的场景。当然,如果是基于分隔符的协议那么不需要ReplayingDecoder来解决拆包粘包,头部数据作为长度的数据格式也不需要ReplayingDecoder,netty提供了其他更方便的工具。但是,遇到长度开始时不确定,是通过接收前数个字段后,才能算出长度的数据格式。或者遇到把长度放中间的数据格式。就需要用到ReplayingDecoder来解决这个问题。

ReplayingDecoder的特点就是可以保存当前的读取状态,这个状态是自定义的。

​​​​​​​如何使用

我们需要extends ReplayingDecoder<StateClass>

 

StateClass是自定义的enum (通常) 代表读取一条数据的进度


@Override

       protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {

 

ReplayingDecoder这里的ByteBuf in的类型是ReplayingDecoderByteBuf

他的不同之处是:当调用其read方法时,如果接受的数据长度小于期待read的数据长度,会抛出一个REPLAY异常

ReplayingDecoder会接收到这个异常后会将ByteBuf的读指针回退到checkpoint的位置

通过checkpoint(State state)方法可以记录下当前的状态以及读指针的位置

通过state()方法可以取得当前的状态,以助于跳转到相应代码的位置。

示例

下面是示例,示例中的State代表待读的内容,也可以自己改为代表已经读取的内容


       @Override

       protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {

              switch(state()){

              case BEGIN:

                     checkpoint(UTC_TIME);

              case UTC_TIME:

                     byte[] utcByte = new byte[4];

                     in.readBytes(utcByte);

                     curUTC = ByteUtils.getDateByUnixTimeStampByte(utcByte);

                     checkpoint(ID);

              case ID:

                     curId = new byte[12];

                     in.readBytes(curId);

                     checkpoint(FrameParseState.DATA_TYPE);

                     …//省略

              default:

                     throw new UnexpectedException("case default不应该到达的位置");

              }

       }

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值