MessageToMessageDecoder粘包

java 复制代码
import java.time.LocalDateTime;
import java.util.*;
import org.apache.commons.lang.time.DateUtils;

import com.liangxs.commom.HexUtils;
import com.liangxs.commom.SpringUtils;
import io.netty.buffer.Unpooled;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import com.liangxs.logger.Logger;
import com.liangxs.logger.LoggerFactory;
import io.netty.util.ReferenceCountUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;

 
public class DianciCustomDecoder extends MessageToMessageDecoder<ByteBuf>{
  
  private byte[] remainingBytes;//剩下的bytes
  private ByteBuf currBB = null;//组合后的新ByteBuf 
  Logger log = LoggerFactory.getLogger(LoggerFactory.MY_INFO_LOG);

  // 超时
  @Override
  public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
    super.userEventTriggered(ctx, evt);
    if (evt instanceof IdleStateEvent) {
      IdleStateEvent e = (IdleStateEvent) evt;
      if (e.state() == IdleState.WRITER_IDLE) {
      } else if (e.state() == IdleState.READER_IDLE) {
   			ctx.channel().close();
      }
    }

  }

  // 连接成功
  @Override
  public void channelActive(ChannelHandlerContext ctx) throws Exception {
    String channelId = ctx.channel().id().asLongText();
  
  }

  // 断开
  @Override
  public void channelInactive(ChannelHandlerContext ctx) throws Exception {
    state = false;
    SpringUtils.getBean(com.liangxs.dbapi.javaDyAdmin.DianchiDataParseService.class).setChannel(null);
    String channelId = ctx.channel().id().asLongText();
    ctx.close();
    super.channelInactive(ctx);
  
  }
 
 protected void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception {
 /***
 每次有数据到来时产生新数据的ByteBuf容易粘包。经发现最大接收数据一次在2000多字节,大于这个数在下一次接收,但它们又需要是一个整体来解析。
 我们用一个全局BUF变量来组装每次请求的进行重新组合成一个buf


*/
         
        if(remainingBytes == null) {
            currBB = msg;
        }else {
        	//根据remainingBytes余下的长度+msg中可读取的长度构建一个新的tb数据,并用余下的字节填充tb
            byte[] tb = new byte[remainingBytes.length + msg.readableBytes()];
            //将remainingBytes值复制给tb
            System.arraycopy(remainingBytes, 0, tb, 0, remainingBytes.length);
            /***
			将msg新数据读取到vb变量中将填充到tb中,将tb转为buffer对象给currBB 
			***/
            byte[] vb = new byte[msg.readableBytes()];
            msg.readBytes(vb);
            System.arraycopy(vb, 0, tb, remainingBytes.length, vb.length);
            currBB = Unpooled.copiedBuffer(tb);
        }
         
        while(currBB.readableBytes() > 0) {
           //循环判断是否还有可读取的
            if(!dodecode(ctx, currBB, out)) {//没有可读取的数据了则退出
                break;
            }
        }
       
        if(currBB.readableBytes() > 0) {
        	//currBB余下的字节长度
            remainingBytes = new byte[currBB.readableBytes()];
            //将currBB读取到remainingBytes中
            currBB.readBytes(remainingBytes);
        }else {
            remainingBytes = null;
        }

 }
  protected boolean  dodecode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {

     if (in.readableBytes() > 3) {//可读取大于3个字节,因为协议头是由一个字节标识+2个字节的数据长度标识组成,
        in.markReaderIndex();//打上读取标记
        byte head =  in.readByte();
        int length = in.readShort();
        /****因为协议中的数据长度是包含头的长度,所以判断可读取数据长度数据减3**/
        if ( in.readableBytes() < length - 3) {
          // 数据长度不够重置readerIndex到上面标记的位置
          in.resetReaderIndex();
          return false;
        }  
         if(in.readableBytes() > 0)//还有可读的可能在下一个包中所以返回TRUE
            return true;
        return false;
       } 
     return false;
    //ReferenceCountUtil.release(in);
  }
}
相关推荐
xcl09253 小时前
北京24小时自助健身房系统软件开发实战:从架构到部署全流程指南
java·spring boot·架构
一 乐4 小时前
动漫书销售商城|基于springboot + vue动漫书销售商城(源码+数据库+文档)
java·数据库·vue.js·spring boot·毕业设计
卓怡学长5 小时前
w214基于jsp知道特产网
java·intellij-idea
步行cgn5 小时前
Spring 注解使用详解
java·spring
一条小小yu5 小时前
Spring IoC的理解
java·后端·spring
落魄实习生5 小时前
Agent Scope Java 2.x 系列【7】工具使用
java·开发语言·ai
旺仔学长 哈哈5 小时前
springboot钓鱼爱好者交流平台APP设计与实现
java·spring boot·mysql·充电桩管理系统
自强的小白7 小时前
核心功能(Service接口)
java·mybatis
乌暮8 小时前
深入理解 Java 泛型:把「万能盒子」用对、用稳
java·开发语言·后端·学习