Netty接收被拆分过的包
问题:
在使用Netty进行自定义协议(发送数据前在数据前加上4字节的长度)TCP客户端操作,,连接到服务器后,接收到服务器返回的数据超过了最大缓冲区进行了拆包,导致在Decoder内接受到的数据不完整,需要分次进行读取,然后读取完成后再往inbound内推。
自定义协议:
在业务数据前加上4字节的长度数据,如果业务数据长度是10字节,则最后接受到的数据应该是14字节
处理逻辑是这样的:
在Decoder里,对接收到的数据进行完整性判断。
- 自定义一个局部变量
dataLen
代表业务数据的长度,初始化为-1 - 有数据进入,判断
dataLen
是否是-1,如果是,则是第一批数据进入,如果不是,则是追加的数据 - 通过
in.readableBytes()
来判断当前数据量是否与业务的数据总量一直,如果不一致,则调用in.resetReaderIndex()
重置读取index,下次继续从0开始读。 - 当总的数据量与业务上的数据量一致,则通过
list.add()
方法,往上抛出数据,并设置dataLen=-1
保证下次的判断。
直接上解决代码:
public class Decoder extends ByteToMessageDecoder {
static Logger logger = LoggerFactory.getLogger(Decoder.class);
//根据自定义的协议,得到前4个字节的数据来计算总的数据长度
int dataLen = -1;
@Override
protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf in, List<Object> list) throws Exception {
byte[] dataBytes = new byte[in.readableBytes()];
in.readBytes(dataBytes);
logger.info("接收到tcp数据");
if (dataLen == -1) {
//取4个字节的数据进行数据的长度计算
byte[] lenBuff = AppUtils.subByte(dataBytes,0,4);
dataLen = AppUtils.bytesToIntLittle(lenBuff,0);
logger.info("数据长度为:" + (dataLen + 4));
if (dataBytes.length == dataLen + 4) {
logger.info("数据完整,释放");
list.add(dataBytes);
dataLen = -1;
}else {
logger.info("数据不足,继续等待接受,总长度:"+(dataLen + 4)+",当前长度:" + dataBytes.length);
//这一步很重要,如果前面已经read过了数据,则buf的读取索引会相应的移动,因为当前数据并不完整,所以重置所以为0,下次继续从0开始读
in.resetReaderIndex();
}
}else {
if (dataBytes.length == dataLen + 4) {
logger.info("数据完整,释放");
list.add(dataBytes);
dataLen = -1;
}else {
logger.info("数据不足,继续等待接受,总长度:"+(dataLen + 4)+",当前长度:" + dataBytes.length);
in.resetReaderIndex();
}
}
}
}