又一次发现公司同事用netty竟然都不处理粘包分包的问题,出了问题都不知道怎么回事,呵呵哒。sp厂商反馈数据已推送至我方提供的地址,但未收到我方的应答,正常推送了一次,又重试三次,都没有收到我方应答。
看了下代码,又跟踪了几条日志,发现sp数据确实有推送,只是我方解析失败。好多数据都是几条信息拼一起过来的,我方只按照头部长度解析了一条,导致许多数据都没有正常更新;还有部分数据是分两次过来的,本来应该放在一起解析一次,我方却解析了两次,自然失败了。
看了下报文约定,基本是这个样子,头部是总长度+固定的命令+序列号+报文数据。
这种自定义的,我一般使用 ByteToMessageDecoder来处理,要注意结合自定义报文约定,这里主要判定头长度和指定命令。
比较简单,查看日志数据已经正常处理了,粘包数据会按报文约定分成多条数据处理,分包问题会等到数据到达指定长度时正确处理。netty用起来很简单,但数据还是要小心处理。/**
* 基本长度(4+4+12) 4:总长度 4:命令标识 12:序列号
*/
private static final int BASE_LENGTH = 20;
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
LOG.debug("decode channelId:{}",ctx.channel().id().asShortText());
if (in.readableBytes() <= BASE_LENGTH) {
LOG.debug("readables:{} channelId:{}",in.readableBytes(),ctx.channel().id().asShortText());
return;
}
int length, command;
while (true) {
in.markReaderIndex();
length = in.readInt();
command = in.readInt();
LOG.debug("length:{},command:{}, channelId:{}",length,command,ctx.channel().id().asShortText());
if (length > BASE_LENGTH && command == 0xF) {
LOG.debug("find command:{},channelId:{}",command,ctx.channel().id().asShortText());
break;
}
in.resetReaderIndex();
byte temp = in.readByte();
LOG.debug("skip a byte:{},channelId:{}",temp,ctx.channel().id().asShortText());
if (in.readableBytes() <= BASE_LENGTH) {
LOG.debug("length:{} less than 20,channelId:{}",in.readableBytes(),ctx.channel().id().asShortText());
return;
}
}
in.resetReaderIndex();
if (in.readableBytes() < length) {
LOG.debug("can read:{} less than length:{},channelId:{}",in.readableBytes(),length,ctx.channel().id().asShortText());
return;
}
byte[] data = new byte[length];
in.readBytes(data);
LOG.debug("success,length:{} data:{},channelId:{}",length,data,ctx.channel().id().asShortText());
out.add(data);