Java 如何从InputStream读取二进制协议?

Java 如何从InputStream读取二进制协议?,java,serial-port,protocols,inputstream,binary-data,Java,Serial Port,Protocols,Inputstream,Binary Data,我试图用Java从串行端口读取二进制协议。我使用从串行端口读取数据 该协议是用于GPS接收机的SiRF二进制协议。结构如下: 前两个字节是0xA0和0xA2,它们定义了数据帧的开头 接下来的两个字节是有效负载长度n 接下来的n个字节是有效负载 最后两个字节是0xB0和0xB3,它们定义了数据帧的结尾 虽然这种结构非常简单,但我无法正确读取数据。我尝试了两种不同的方法: 我编写了一个线程,它读取InputStream,并将输入与0xA0进行比较。如果匹配,则线程读取下一个字节并与0xA2进行比

我试图用Java从串行端口读取二进制协议。我使用从串行端口读取数据

该协议是用于GPS接收机的SiRF二进制协议。结构如下:

  • 前两个字节是0xA0和0xA2,它们定义了数据帧的开头
  • 接下来的两个字节是有效负载长度n
  • 接下来的n个字节是有效负载
  • 最后两个字节是0xB0和0xB3,它们定义了数据帧的结尾
虽然这种结构非常简单,但我无法正确读取数据。我尝试了两种不同的方法:

  • 我编写了一个线程,它读取
    InputStream
    ,并将输入与0xA0进行比较。如果匹配,则线程读取下一个字节并与0xA2进行比较。如果再次匹配,它将读取接下来的两个字节并计算有效负载长度。之后,它读取长度为n字节的有效负载。最后,它读取最后两个字节,并将它们与0xB0和0xB3进行比较。当所有内容都匹配时,它从输入创建一个十六进制字符串并将其保存到队列中。这是我的密码:

    try {
        byte[] size = new byte[2];
        byte[] checkSum = new byte[2];
        byte[] packet;
        int bytesRead = -1;
        while (in.available() > 0) {
            if (getInput() == 0xA0) {
                if (getInput() == 0xA2) {
                    System.out.print("160,162,");
                    bytesRead = in.read(size);
                    int payLoadLength = (size[0] << 8) | (size[1] & 0xFF);
                    byte[] payload = new byte[payLoadLength];
                    bytesRead = in.read(payload);
                    bytesRead = in.read(checkSum);
                    if (getInput() == 0xB0) {
                        if (getInput() == 0xB3) {
                    System.out.println("out");
                    packet = new byte[2 + 2 + payLoadLength + 2 + 2];
                    packet[0] = (byte) START_1;
                    packet[1] = (byte) START_2;
                    packet[2] = size[0];
                    packet[3] = size[1];
                    for (int i = 0; i < payload.length; i++) {
                        packet[i + 4] = payload[i];
                    }
                    packet[packet.length - 4] = checkSum[0];
                    packet[packet.length - 3] = checkSum[1];
                    packet[packet.length - 2] = (byte) END_1;
                    packet[packet.length - 1] = (byte) END_2;
                    StringBuffer hexString = new StringBuffer();
                    int[] output = new int[packet.length];
                    for (int i = 0; i < packet.length; i++) {
                        output[i] = 0xFF & packet[i];
                        hexString.append(Integer.toHexString(output[i]));
                    }
                    TransportMessage tm = new TransportMessage(hexString.toString());
                    boolean b = queue.offer(tm);
                    System.out.println(hexString.toString().toUpperCase());
                    if(!b)
                        System.err.println("TransportMessageQueue voll!");
                }
            } else {
                System.out.println();
            }
        }
    } 
        }
    } catch (IOException e) {
        System.out.println(e);
    }
    
    试试看{
    字节[]大小=新字节[2];
    字节[]校验和=新字节[2];
    字节[]数据包;
    int字节读取=-1;
    while(in.available()>0){
    如果(getInput()==0xA0){
    如果(getInput()==0xA2){
    系统输出打印(“160162”);
    字节读取=英寸读取(大小);
    
    int payLoadLength=(大小[0]如果使用RXTX,则可以设置一个侦听器,当数据可用时,该侦听器将异步通知您:

    serial.notifyOnDataAvailable(true);
    serial.addEventListener(this);
    
    public void serialEvent(final SerialPortEvent arg0) {
        try {
            if (arg0.getEventType() == SerialPortEvent.DATA_AVAILABLE) {
                //read from the input stream;
            }
        } catch (final Exception e) {
            e.printStackTrace();
        }
    }
    

    一般来说,当你从输入流中读取数据时,你应该抽象出“数据包”的概念,而不是使用“可用”函数——只需从数据包中读取足够的数据以确定其长度,然后只需使用“读取(字节[])”,将完整的数据包读入缓冲区。(更高级的说明是,“读取”可读取的字节数少于所需的字节数,因此应在循环中使用。

    如果使用RXTX,则可以设置一个侦听器,当数据可用时,该侦听器将异步通知您:

    serial.notifyOnDataAvailable(true);
    serial.addEventListener(this);
    
    public void serialEvent(final SerialPortEvent arg0) {
        try {
            if (arg0.getEventType() == SerialPortEvent.DATA_AVAILABLE) {
                //read from the input stream;
            }
        } catch (final Exception e) {
            e.printStackTrace();
        }
    }
    

    一般来说,当你从输入流中读取数据时,你应该抽象出“数据包”的概念,而不是使用“可用”函数——只需从数据包中读取足够的数据以确定其长度,然后只需使用“读取(字节[])”,将完整的数据包读入缓冲区。(更高级的说明是,“读取”可以读取的字节数少于所需的字节数,因此应该在循环中使用。)

    java.io.DataInputStream用于此类任务。java.io.DataInputStream用于此类任务。我已经尝试过此方法。in本应使其更清晰。这样,我仍然缺少一些数据帧。我发现问题:这是额外的循环
    (in.available()>0){}
    围绕读取过程。您编写了“当数据可用时异步通知您”,这让我产生了怀疑…在删除此循环后,它似乎按预期工作。谢谢!是的,我从未好好利用过“available”函数。我已经尝试了此操作。In本应使其更清晰。这样,我仍然缺少一些数据帧。我发现了问题:这是围绕读取过程的附加循环
    (In.available()>0){}
    。您编写了“当数据可用时异步通知您”这让我产生了怀疑…在删除这个循环后,它似乎按预期工作。谢谢!是的,我从来没有好好利用过“可用”功能。