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);
  }
}
相关推荐
2601_963870172 分钟前
【计算机毕业设计】基于Spring Boot的社区老年大学课程报名与学习系统的设计与实现
java·spring boot·学习
llwszx15 分钟前
【Java/Go后端手撸原生Agent(第七篇):Token预算管理 + 滑动窗口上下文裁剪】
java·后端·python·agent开发·上下文工程·上下文裁剪·滑动窗口裁剪
weixin_BYSJ19871 小时前
springboot3家政平台小程序--附源码00904
java·javascript·spring boot·python·django·flask·php
梦幻通灵1 小时前
Java中finally失效的几种情况【持续更新】
java·开发语言
月落归舟2 小时前
SpringMVC 多种响应返回方式
java·开发语言
吃饱了得干活2 小时前
JVM垃圾回收:从新生代到ZGC,从理论到调优
java·jvm·后端
长不胖的路人甲2 小时前
二叉排序树(BST)Java 完整实现 + 删除思路详解
java·开发语言·算法
大模型码小白2 小时前
Java 部署:Jenkins Pipeline 构建 Java 项目(自动化)
java·人工智能·python·机器学习
长不胖的路人甲2 小时前
可达性分析法(根搜索算法)完整详解
java·jvm·算法
笨笨饿2 小时前
#102_Codex无在VSCold无法打开
java·c语言·数据库·笔记