开发部标JT808GPS平台,使用java语言开发网关程序,目前普遍使用Netty。众所周知,TPC编程要解决粘包和拆包问题。现提供一种解决方案如下:
public class ProtocolDecoder extends ByteToMessageDecoder {
private Logger logger = Logger.getLogger(ProtocolDecoder.class);
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
if (in == null) {
return;
}
in.markReaderIndex();
ByteBuf byteBuf = in.asReadOnly();
byteBuf.markReaderIndex();
while (in.isReadable()) {
in.markReaderIndex();
int packetBeginIndex = in.readerIndex();
byte tag = in.readByte();
// 搜索包的开始位置
// 处理黏包和拆包
if(tag==0x7E){
if(!in.isReadable()){
in.resetReaderIndex();
return;
}
else{
tag = in.readByte();
// 防止是两个0x7E,取后面的为包的开始位置
// 寻找包的结束
while (tag != 0x7E) {
if (in.isReadable() == false) {
in.resetReaderIndex(); // 没有找到结束包,等待下一次包
// logger.error("半包:"+Tools.toHexString(data));
return;
}
tag = in.readByte();
}
int pos = in.readerIndex();
int packetLength = pos - packetBeginIndex;
if (packetLength > 2) {
byte[] tmp = new byte[packetLength];
in.resetReaderIndex();
in.readBytes(tmp);
//logger.error("收到数据 = " + Tools.toHexString(tmp));
T808Message message = new T808Message();
message.readFromBytes(tmp);
out.add(message); // 触发接收Message的事件
// return message;
} else {
// 说明是两个0x7E
logger.error("收到2个7E,Index:" + in.readerIndex() + " 长度 = " + packetLength + " 末尾数据 = " + Tools.toHexString(new byte[]{tag}));
in.resetReaderIndex();
in.readByte(); // 两个7E说明前面是包尾,后面是包头
}
}
}else if (in.isReadable() && byteBuf.isReadable()){
byte[] bytes = new byte[byteBuf.readableBytes()];
byteBuf.readBytes(bytes);
logger.error( "(" + ctx.channel().id().asLongText() + "," + ctx.channel().remoteAddress() + ") Index:" + in.readerIndex() + " 存在非法数据:" + Tools.toHexString(bytes));
}
}
return;
}
}