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);
}
}
MessageToMessageDecoder粘包
于 2024-04-14 14:52:03 首次发布
这篇文章介绍了DianciCustomDecoder类,一个基于Netty的消息解码器,用于处理接收到的分片数据,防止粘包,并处理连接状态和超时事件。
摘要由CSDN通过智能技术生成