Closed JamesLiAndroid closed 6 years ago
粘包拼包需要结合具体的协议来解决。 大致流程就是收到数据后先缓存下来,然后找出数据帧头,找出包尾,然后校验整个包是否有效,有效就把数据包分发出去(最好在其他线程分发,不要阻塞接收的线程),无效就要考虑是要放弃掉整个包,还是返回到帧头后的下一个字节,继续找帧头。
下面是我具体项目的一个例子,用到ByteBuffer来缓存数据。 我这个项目的数据包是固定7字节长度的,而且有固定的帧头帧尾,所以校验出错的话,我就舍弃掉整个包了,如果是动态包长度的,更多是需要返回帧头后那个字节,再重新找帧头。
public void receive(byte[] data, int length) {
//LogPlus.w("收到数据=" + ByteUtil.bytes2HexStr(data, 0, length));
mByteBuffer.put(data, 0, length);
checkData();
}
// 起始位 仓口ID号 特征码 效数据 校验位 数据尾
// 0x1b x x x x 0D 0A
private void checkData() {
mByteBuffer.flip();
byte b;
byte[] twoBytes = new byte[2];
int frameStart;
int frameEnd;
// 必须比包长度大
while (mByteBuffer.remaining() >= Protocol.PACKAGE_LENGTH) {
mByteBuffer.mark(); // 标记一下开始的位置
// 标记一个第一个元素
frameStart = mByteBuffer.position();
b = mByteBuffer.get();
if (b != Protocol.FRAME_HEAD) { // 第1个byte要0x1B
continue;
}
// 跳过 仓口ID号 特征码 效数据 校验位 (1 1 1 1)
mByteBuffer.position(mByteBuffer.position() + 4);
// 数据尾
mByteBuffer.get(twoBytes);
frameEnd = mByteBuffer.position();
// 数据尾符合规则
if (twoBytes[0] == Protocol.FRAME_FOOT_0 && twoBytes[1] == Protocol.FRAME_FOOT_1) {
mByteBuffer.position(frameStart + 1);
int toDiff = mByteBuffer.get(); // 仓口ID号
toDiff = toDiff ^ mByteBuffer.get();// 特征码
toDiff = toDiff ^ mByteBuffer.get();// 效数据
byte check = mByteBuffer.get(); // 校验位
if (check == (byte) toDiff) {
// 校验成功
// 拿到整个包
mByteBuffer.reset();
byte[] data = new byte[Protocol.PACKAGE_LENGTH];
mByteBuffer.get(data);
if (getValidDataCallback() != null) {
getValidDataCallback().onReceiveValidData(data);
}
} else {
//校验失败,舍弃这个包
mByteBuffer.position(frameEnd);
}
} else {
// 不符合就跳到第二个为重新来
mByteBuffer.position(frameStart + 1);
}
}
// 最后清掉之前处理过的不合适的数据
mByteBuffer.compact();
}
目前我这边的协议是这样的(PS:直接处理字符串)
setcfg{OpenDoor=0;}setcfg\r\n
大括号内的内容是可变的,也就是整个数据包长度不固定
判断 }setcfg\r\n 的位置,然后往前找头 setcfg{ , 最后直接取中间值。
我现在的问题是,尾部能判断,如果尾部不全,从尾部往前的全部舍弃, 但是头部很多时候不全,甚至会出现乱码的情况(一般乱码是FF这样的hex字符),这种情况下如何处理,舍弃吧,中间数据还是完整的,但是不舍弃就错过了完整的数据。
最极端的我想的是直接那中间的OpenDoor=0;在字符串中间进行判断,但是几十个命令,都去判断的话,执行时间上就把握不了了。
所以还是向您请教下!谢谢!
@JamesLiAndroid 波特率设置的合适不?发的字符串命令包不包含中文等字符?
感觉直接用字符串来给串口发命令不是很好,处理起来比固定协议的要麻烦。
你看看能不能这样,还是按照原始字节数组来处理,先弄出setcfg
的和setcfg\r\n的byte[]常量,收到数据后,直接从原始数据中找出
setcfg的和setcfg\r\n
的byte[]数组的位置,找到后再抽出来转成字符串。
@licheedev
字符串发送的时候是直接转byte发送的,您的意思是按照hex处理完再转字符串?
还忘了两个很重要的问题:
想请教下关于粘包、拼包的问题,我好多次收到下位机发来的指令信息过长,导致信息截断,无法完整读取,这样的情况下该如何进行处理?