处理帧头帧尾,识别有效信息
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* TCP/IP数据解码器
*/
@Slf4j
@Component
public class MessageDecoderHandler extends ByteToMessageDecoder {
private final ByteBuf header;
private final ByteBuf ender;
public MessageDecoderHandler() {
this.header = Unpooled.buffer();
header.writeByte(0xAA);
header.writeByte(0x55);
this.ender = Unpooled.buffer();
ender.writeByte(0x55);
ender.writeByte(0xAA);
}
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
// 显示十六进制的接收码
log.info("协议收到数据为{}", ByteBufUtil.hexDump(in));
// 调用decode方法,去除帧头和帧尾
ByteBuf childBuf = decode(in);
// 如果获得有效数据
if (childBuf != null) {
// 将有效数据备份加入接收列表
out.add(childBuf.copy());
}
}
protected ByteBuf decode(ByteBuf buf) {
// 帧头起始位置
int sliceStart = 0;
// 帧尾起始位置
int sliceEnd = 0;
// 数据帧
ByteBuf frame = null;
// 帧头是存在
if (header != null) {
// 获取帧头位置
int index = ByteBufUtil.indexOf(header, buf);
// 帧头第一次出现位置找到
if (index > -1 && index < buf.capacity()) {
// 舍弃帧头前面的数据
buf.readerIndex(index);
}
// 将帧头位置保存
sliceStart = index;
}
// 帧尾存在
if (ender != null) {
// 获取帧尾的起始位置
int endindex = ByteBufUtil.indexOf(ender, buf);
// 保存帧尾的位置
sliceEnd = endindex;
// 帧尾找到,并且在帧头的后面
if (endindex > -1 && endindex > sliceStart && endindex < buf.capacity()) {
// 计算数据帧的长度:帧尾的起始位置-帧头的起始位置-帧头的长度
assert header != null;
int length = sliceEnd - sliceStart - header.readableBytes();
// 获取数据子帧
frame = buf.slice(sliceStart + header.readableBytes(), length);
// 将reader索引设定到帧尾的后面
buf.skipBytes(sliceEnd - sliceStart + ender.readableBytes());
// 将数据帧返回
return frame;
}
}
//去掉剩余的垃圾数据
if (sliceEnd == -1) {
//将可读数据设置为0
buf.skipBytes(buf.readableBytes());
}
return null;
}
}