字节流数据解析

本文介绍了一种解决Linux串口通信中丢包问题的方法。通过对原有解析代码的分析,发现当数据段含有帧头时会导致解析失败。通过重新设计解析逻辑,确保即使数据包含帧头也能正确解析。

各种与硬件底层相关的数据大都是字节型的传输方式,如串口,如果协议定的不好,解析写不好,就会发生丢包。近期在做linux串口的数据通讯时,发生了让人头疼的丢包,后分析解析代码发现一旦数据段中含有帧头便会解析不到数据,通过一上午的调试,写了一个新的解析。

#include <stdio.h>

//帧头 长度 命令 数据 校验 (帧尾:可以不需要,也可以当做简单的校验)
//解析思路:接收到帧头后,根据长度来读取数据,最后校验(如果数据中有帧头则会跳过,不影响解析)
//示例:帧头-0xaa,0x02 长度-0x07 帧尾-0xbb

uint8_t buff[24] ={0x21,0xAA,0xAA,0x02,0x07,0xAA,0xBB,0xBB,0xff,0x34,0x99,0xbb,
                   0xaa,0xAA,0x02,0x07,0xA7,0xB7,0xaa,0xff,0x14,0xa9,0xbb,0x00
                  };

int main(int argc, char *argv[])
{
    uint8_t i=0;
    uint8_t tbuf = 0;

    uint8_t cnt = 0;//解析状态标记
    uint8_t scnt = 0;//数据段角标
    uint8_t slen = 0;//数据段长度
    uint8_t *psbuf = NULL;//数据段缓冲区

    while(i<24)
    {
        //printf("%x ",buff[i]);

        tbuf = buff[i];

        if((tbuf == 0xAA)&&(cnt == 0))//可能第一个头
            cnt = 1;

        switch(cnt)
        {
        case 1:
            if(tbuf == 0x02)//第二个头
                cnt = 2;
            break;
        case 2:
            slen = tbuf;//读取长度
            psbuf = (uint8_t*)malloc(slen*sizeof(uint8_t));//开辟空间
            scnt = 0;//复位数据段缓冲区

            cnt = 3;
            printf("slen:%d\n",slen);
            break;
        case 3:
            psbuf[scnt] = tbuf;
            if(scnt == slen-1)
            {
                cnt = 0;//接收到最后一个字节就复位
                printf("finished!\n");//解析完毕

                for(int k=0;k<slen;k++)
                    printf("%x ",psbuf[k]);
                printf("\n");

                free(psbuf);//释放动态内存
            }
            scnt++;
            break;
        default:
            break;
        }

        i++;
    }
    printf("\n");
    return 0;
}
  • 调试经验:在qt中不要强行想把协议和串口类分开,因为实现起来比较困难,虽然可以利用回调和继承实现但是如果用到ui,需要在回调和继承里更新ui就非常麻烦。
<think>首先,用户在查询“字节流数据的范围”。我需要解析这个问题。用户说:“我想查询字节流数据的范围”,意思是“我想查询字节流数据的范围”。 回顾提供的引用: - 引用[1]:讨论Java中的字节输入流,包括使用FileInputStream读取文件字节。 - 引用[2]:关于使用Socket读取字节流数据,涉及解析数据包。 - 引用[3]:解释读取字节流的方式,提到read方法返回有效字节个数或-1(EOF)。 - 引用[4]:关于MySQL数据类型,如整数类型。 关键点:用户的问题似乎是关于字节流数据的值范围或类型范围。字节流数据通常是一系列字节,每个字节是一个8位无符号整数,范围从0到255(或十六进制0x00到0xFF)。 在计算机科学中,一个字节(byte)占8位,所以值的范围是: - 最小值:0(二进制00000000) - 最大值:255(二进制11111111) 这是由于使用无符号表示;在Java中,字节(byte)类型是有符号的,范围是-128到127,但当读取字节流时,它们通常被视为原始字节数据,值从0到255。 在字节流处理中,如引用[1]和[引用[3]所示,读取字节时会得到整数值,并且read方法返回-1表示流的结束(EOF)。 引用[3]明确说: “I.read(bytes,0,bytes.length)的返回值表示读到的有效字节个数,如果I.read(bytes,0,bytes.length)=-1,表示EOF表示,没有任何字节可取或者已读取完毕”,意思是返回值表示读取到的有效字节数,如果返回-1,表示结束。 所以,字节流数据本身的范围是每个字节值从0到255,但读取方法的返回值可以是从-1(表示EOF)到正数(表示读取的字节数目)。 用户说“字节流数据的范围”,可能指的是单个字节值的范围,或者整个流的范围。但从上下文看,似乎是询问字节数据的值范围。 在引用[1]中,提到中文编码占用多个字节,暗示字节值范围影响字符表示。 在引用[4],讨论MySQL数据类型,如INTEGER的范围,但引用[4]是关于MySQL的数值类型,不是直接关于字节流。 用户的问题是“字节流数据的范围”,所以我应该专注于字节流数据范围。 定义清楚: - 字节流数据:一个序列的字节。 - 每个字节:8位,无符号时范围0-255;有符号时范围-128到127(在Java中)。 在流处理中: - 当读取字节时,例如使用FileInputStream.read(),它返回一个整数:值在0到255之间表示字节值,或-1表示EOF。 - 当读取到一个字节数组时,每个元素是字节值。 所以,字节流数据的有效值范围是每个字节从0到255,EOF用-1表示。 在数据表示中,字节值用于表示各种数据类型,如整数、字符等,但用户的查询是字节流数据本身的范围。 结构化我的回答: 1. **解释字节流数据的范围**:每个字节值范围0-255(无符号),但在Java中,字节类型是带符号的,因此实际值可以是-128到127,但当读取为整数时,0-255用于表示数据。 在Java中,read()方法返回一个int,其中低8位是字节值,所以值在0到255之间,或者-1。 例如,在引用[1]的代码中: - fileInputStream.read() 返回一个int,如果非负,则是字节值(0-255)。 - 读取到字节数组时,数组元素是byte类型,值-128到127。 但当使用 new String(bys, 0, len) 时,它会解释字节数组作为字符编码的一部分。 但用户的问题是关于数据范围,而不是字符表示。 2. **涉及流的范围**:流的长度或大小,但字节流本身没有固定大小;它取决于数据源(文件、网络等)。最小大小是0字节(空流),最大理论上没有限制。 在读取时,read方法返回读取的字节数,可以是0(如果无数据但未结束)或正数。 从引用[3]:read(bytes) 返回读取的字节数,如果为-1表示结束。 所以,返回值的范围:-1(EOF),或从0到数组长度的整数。 但用户说“字节流数据的范围”,可能更倾向于字节值本身。 3. **在数据库中上下文**:引用[4]提到MySQL数据类型,如INTEGER的范围,但字节流数据不是直接存储为那样的;它通常是BLOB(Binary Large Object)。在MySQL中,BLOB类型存储二进制数据,每个字节范围0-255。 例如,MySQL中的BLOB类型存储字节序列。 所以,字节流数据的范围在存储时每个字节0-255。 总结字节流数据的范围: - 单个字节值范围:0到255(十进制),或十六进制00到FF。 - 在Java或其他语言中处理时,可能使用有符号byte类型(-128到127),但原始数据是0-255。 - 流的长度:从0字节到非常大,取决于实现(如文件大小或网络数据)。 回答用户的问题:我需要明确范围的含义。 由于用户引用涉及Java IO,我应该基于Java上下文回答。 在Java中: - 当读取字节流时,byte数据类型是8位有符号整数,范围从-128到127。 - 然而,在输入流中,read()方法返回一个int,其中值在0到255之间表示字节数据,或-1表示结束。 - 因此,字节数据的值范围是0到255。 - 对于字节数组,元素是byte类型,值-128到127,但当解释为原始数据时,对应0-255。 在字符串编码中,字节序列被解释为字符。 但核心范围是0-255 per byte。 回答结构: - 先解释什么是字节流数据:字节序列。 - 然后给出范围:每个字节值从0到255。 - 提及EOF用-1表示,但不是数据值的一部分。 - 在数据库或其他上下文中,类似。 最后,根据系统指令生成相关问题。 系统指令: - 所有行内数学表达式用$...$格式。 - 独立公式用$$...$$格式。 - 使用中文回答。 - 生成相关问题。 - 回答中引用的段落末尾自然地添加引用标识。 在我的回答中,如果有引用内容,末尾加[^n]。 引用来自用户提供的:[^1], [^2], [^3], [^4]。 用户说:“上述引用仅供参考,并不是用户真正的需求,请尽可能多的参考用户上一次的问题和你的回答。” 但这是第一条消息,没有“上一次的问题”;可能是对话开始。 所以,基于当前查询。 最终回答: </think>### 字节流数据的范围 字节流数据(byte stream data)指的是一个序列的字节(byte),每个字节是一个8位的二进制单元。在计算机系统中,字节流常用于文件读取、网络传输或数据库存储等场景(如Java IO操作)。字节流数据的范围主要涉及两个方面:**单个字节值的范围**(即字节数据的取值范围)和**流的整体范围**(如长度或大小)。下面我将逐步解释。 #### 1. **单个字节值的范围** - 每个字节由8位(bit)组成,通常被视为无符号整数(unsigned integer)。其值的十进制范围是: $$0 \text{ 到 } 255$$ 对应的十六进制范围是: $$00\text{H} \text{ 到 } \text{FF}H$$ 这表示每个字节可以存储的值最小为0(二进制 `00000000`),最大为255(二进制 `11111111`)。 - **在编程语言中的处理**: - 在Java等语言中,`byte` 数据类型是带符号的(signed),范围从 $-128$ 到 $127$。但当使用输入流读取字节时(如 `FileInputStream.read()`),方法返回一个 `int` 值: - 如果返回值为 $0$ 到 $255$,表示一个字节数据(读取到的实际字节值)。 - 如果返回值为 $-1$,表示流结束(End of File, EOF),这不是数据值的一部分,而是流的结束标志[^3]。 - 例如,在代码中读取字节时: ```java int byteValue = fileInputStream.read(); // 返回0-255或-1 ``` - 当读取到字节数组(如 `byte[] bys = new byte[1024]`)时,数组元素是 `byte` 类型($-128$ 到 $127$),但原始数据值仍对应无符号范围 $0$ 到 $255$。当转换为字符串或解释时(如 `new String(bys, 0, len)`),系统会根据编码(如UTF-8或GBK)将字节序列解释为字符[^1]。 - **在数据库中的上下文**: - 如果字节流存储于数据库(如MySQL),通常使用BLOB(Binary Large Object)类型。每个字节值范围同样是 $0$ 到 $255$,与文件或网络流一致[^4]。 总结:字节流数据的单个值范围是严格限制的,即 $0 \leq \text{值} \leq 255$(无符号),EOF用 $-1$ 表示。 #### 2. **流的整体范围** - **长度范围(大小)**: - 字节流的最小长度可以是 $0$ 字节(空流或未初始化)。 - 最大长度理论上无上限,取决于数据源(如文件大小、网络数据包大小或系统内存限制)。实际应用中,Java IO操作一次读取的字节数通常限制在数组大小(如1024字节或整数倍),但通过循环可以处理任意长度的流[^1]。 - 读取方法(如 `read(byte[] b)`)返回的字节数范围: - 返回值在 $-1$ 到数组长度之间: - $-1$:表示流结束(EOF)。 - $0$:表示无数据可读(但流未结束)。 - 正整数($1$ 到数组长度):表示实际读取的字节数[^3]。 - 例如,在代码中: ```java byte[] bys = new byte[1024]; int len = fileInputStream.read(bys); // len范围:-1, 或0到1024 ``` - **应用示例**: - 在文件读取中(如引用[1]),字节流长度由文件大小决定。 - 在网络传输中(如引用[2]),字节流可能被解析数据包(packet),长度由协议头指定(例如,头字段 `pktBodySize` 定义包体的字节长度)。 - 在数据库中,BLOB字段可以存储大型字节流,最大长度取决于数据库配置(如MySQL中BLOB类型最大可到4GB)[^4]。 总结字节流数据的范围: - **值范围**:每个字节值介于 $0$ 和 $255$ 之间(无符号),EOF用 $-1$ 表示。 - **长度范围**:流长度从 $0$ 到非常大(理论上无限),但受系统约束影响;读取方法返回值范围在 $-1$ 到数组长度之间。 如果您有具体场景(如文件处理或网络协议),可以提供更多细节,我可以进一步解释优化方法!
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值