android设备与PC端控件进行HID通信的粘包和乱码问题

HID通信的长度受到USB设备速率的影响。‌

对于低速设备(‌LS)‌,‌最大包长为8字节。‌
对于全速设备(‌FS)‌,‌最大包长为64字节。‌
对于高速设备(‌HS)‌,‌最大包长为1024字节。‌
如果使用的是全速设备,‌但需要传输的数据超过64字节,‌如256字节,‌可以通过拆包传输的方式处理,‌即将数据拆分成多个64字节的包进行传输。‌这种拆包传输的方式在HID通信中是一种常用的处理方法1

项目需要Android客户端与PC控件传输数据,数据较长且长度不确定,由于HID通信是面向流的通信且每次最大的传输数据为1024长度的byte数组,面向流的通信是无消息保护边界的,所以如何确定接收的数据的长度是关键问题,在传输中容易出现乱码和粘包的问题。

在TCP数据传输中,解决流式数据传输的粘包/拆包问题的方法主要包括消息长度前置、‌消息定长、‌消息定界符。‌

使用HID通信每次只能传长度为1024的byte数组,如果传输的数据不够1024则用0补全,如果传输的数据超过了1024需要分割为多个数据包进行传输。接收时不够1024长度时需要补0,超过1024时需要接受多个数据包,最后将多个数据包进行累加,根据消息定界符计算数据的长度,截取界定符中间的数据为最终接受的数据。
第一种方式:接收方首先接收到传输数据的字符数组的长度,其次读取上次接收到的长度的byte数组的数据,即为需要处理的数据。

@Override
    public void run() {
        if ( hid == null )
            return;
        hid.open();
        while (true) {
            if (isStop) {
                break;
            }
            try {
                ByteArrayOutputStream bytearray = new ByteArrayOutputStream();
                ByteArrayOutputStream outs_bytearray = new ByteArrayOutputStream();
                int len = 0;
                byte[] bytelen = new byte[1024];
                byte[] buffer = null;
                //接收待处理数据的长度
                len = hid.read(bytelen);
                if (len < 4) {
                    byte[] erroutbytes = "error".getBytes();
                    hid.write(intToByteArray(erroutbytes.length));
                    hid.write(erroutbytes);
                    logger.error("hid error");
                } else {
                    //获取待处理数据的实际长度
                    int reallen = byteArrayToInt(bytelen, 0);
                    //读取制定长度的数据
                    byte[] revdata = new byte[reallen];
                    hid.read(revdata);
                    if (sendMessage != null) {
                        byte[] outbytes = sendMessage.SendByteData(handler, revdata);
                        if (outbytes == null) {
                            hid.write(intToByteArray(0));
                            logger.error("hid send error");
                        } else {
                            hid.write(intToByteArray(outbytes.length));
                            hid.write(outbytes);
                        }
                    }
                }
                bytearray.close();
                outs_bytearray.close();
            } catch (Exception e) {
                logger.error("hid exception:", e);
            }

        }
    }

第二种方式:
Android客户端和PC控件端约定数据以begin01XXXend的格式传输,即最后截取的时begin01和end之间的数据。这样将会存在一个问题,就是多个数据包中可能出现多个end的情况,就无法准确计算出数据的末尾。针对这个问题,我们将数据的结束位设计未byte形式的0,由于传输的数据是字符串,byte形式的0是不可能会出现的。最后 一个包的数据长度小于1024时,会补全多个0,所以我们取第一个0的位置减去end的byte长度的位置,就是最后数据结束的位置,具体查找起始位置和结束位置的代码如下所示:

	// 查找并打印以 "begin" 开头和 "end" 结尾的中间数据
   private void findAndPrintDataBetweenMarkers(byte[] data){
      byte[] begin01Bytes = "begin01".getBytes();
      byte[] endBytes = "end".getBytes();

      int beginIndex = -1;
      int endIndex = -1;

      // 查找开始标记的位置
      for (int i = 0; i <= data.length - begin01Bytes.length; i++) {
         if (startsWith(data, i, begin01Bytes)) {
            beginIndex = i + begin01Bytes.length;
            break;
         }
      }

      // 如果没有找到开始标记,则直接返回
      if (beginIndex == -1) {
         System.out.println("No 'begin' marker found.");
         backToPC(1,"No 'begin' marker found.");
         return;
      }

      // 从开始标记后面继续找结束标记的位置
      for (int i = beginIndex; i < data.length; i++) {
         if (data[i] == 0) {
            endIndex = i-endBytes.length;
            break;
         }
      }

      // 如果没有找到结束标记,则直接返回
      if (endIndex == -1) {
         System.out.println("No 'end' marker found after 'begin'.");
         backToPC(1,"No 'end' marker found after 'begin'.");
         return;
      }

      // 提取并打印中间数据
      byte[] middleData = new byte[endIndex - beginIndex];
      System.arraycopy(data, beginIndex, middleData, 0, endIndex - beginIndex);
      String middleDataString = new String(middleData);
      System.out.println("Middle data between 'begin' and 'end': " + middleDataString);
      handleWaitSignMsg(middleDataString);
      backToPC(0,"receive PDF success");
   }
  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值