关于python中socket如何与硬件设备通信发送16进制指令并做crc16校验

本文介绍在ARM硬件上通过socket客户端发送16进制指令并进行CRC校验的过程,包括Python实现的CRC16校验算法及指令发送流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.需求说明

现有硬件设备arm,上有网板,通过socket客户端发送指令与接收数据并做crc校验,指令类型"01 24 3F 4D EC"等组合的16进制数据,且指令也需要做crc校验,并附加到指令后面。

2.python如何做crc校验

def crc16(data, length):
    my_data = bytearray(2)
    xda = 0xFFFF
    x_poly = 0xA001
    for z in range(length):
        xda ^= data[z]
        for j in range(8):
            x_bit = int(xda & 0x01)
            xda >>= 1
            if x_bit == 1:
                xda ^= x_poly
    my_data[0] = xda & 0xFF
    my_data[1] = xda >> 8
    return my_data

此代码是从C转换过来的,所以可以很好的与底层硬件切合。

3.如何发送指令并使用crc16函数

SendStr = '01 24'
hexValuesSplit = SendStr.split(' ')
bs = bytearray(4)  #一般是1024,不过为了数据整洁,确定大小后可以直接设置大小
i = 0
for my_hex in hexValuesSplit:
    if my_hex != "":
        value = int(my_hex, 16)
        bs[i] = value
        i += 1
tempB = crc16(bs, i)  # 获取校验结果
bs[i] = tempB[0]
bs[i + 1] = tempB[1]
i = i + 2  # 这个是记录数据长度,有时候需要发送
for item in bs:
    print(hex(item))  # 最后两位是校验结果 0x0 0x3b
socket.send(bs)  # 发送

 

<think>我们正在解决一个特定问题:tar.gz压缩包在TCP传输过程中被自动添加CRC校验(可能是传输工具或网络设备的行为),导致解压时出现`gzip: stdin has flags 0x42`错误。根据之前的分析,标志0x42表示文件头中的flags字节被设置为0x42(二进制01000010),这通常意味着有额外的字段(extra field)和CRC16校验。但标准gzip工具可能无法正确处理这种格式,尤其是当这些字段被错误添加时。 用户提到“被自动添加CRC校验”,这可能是由于某些网络设备(如一些负载均衡器或代理)在传输过程中修改了数据包,或者发送方/接收方的应用程序在传输过程中添加了校验和(例如,在自定义TCP应用中)。 解决方案的核心是确保传输的原始性,在接收端修复可能被破坏的文件头。以下是具体步骤: ### 1. **确认问题根源** - 首先,我们需要验证是否真的是传输过程中添加了额外的校验。可以比较发送前和接收后的文件: - 在发送方计算原始文件的MD5/SHA256哈希值。 - 在接收方计算接收到的文件的哈希值。 - 如果哈希值不同,则传输过程中确实有修改。 ### 2. **避免传输过程中的修改** - **使用加密传输协议**:如SCP、SFTP或HTTPS,这些协议会对数据进行封装,避免中间设备修改有效载荷。 ```bash # 使用scp传输(需要SSH服务) scp source_file.tar.gz user@remote_host:/path/to/destination/ ``` - **检查网络设备配置**:如果必须使用TCP,检查中间设备(如代理、防火墙)是否配置了数据包修改(如添加校验和)。如果有,关闭这些功能。 ### 3. **接收端修复损坏的gzip文件** 如果重新传输后问题依旧,或者无法避免传输修改,可以尝试在接收端修复文件。标志0x42通常表示文件头有额外的10字节(extra field)和2字节CRC16(在文件头之后)。我们可以手动移除这些字节: - **步骤1:跳过文件头的前10个字节(extra field)和2字节CRC16(共12字节)?** 实际上,gzip文件头结构如下: - 前10字节是固定头(包含ID1、ID2、压缩方法、标志、时间戳等),其中第4字节就是flags。 - 如果flags的0x04位被设置(即0x04),则后面会跟额外的字段(extra field),其结构为:2字节长度(XLEN)+ XLEN字节的数据。 - 如果flags的0x02位被设置(即0x02),则头后面会跟2字节的CRC16校验(针对文件头)。 由于错误是0x42,即0x40(有extra field)和0x02(有CRC16)的组合。因此,文件头结构如下: 1. 10字节固定头(其中第4字节是0x42) 2. 2字节的XLEN(表示extra field的长度,假设为L) 3. L字节的extra field 4. 2字节的CRC16(针对文件头) 5. 压缩数据 所以,我们需要跳过固定头(10字节)+ XLEN(2字节)+ extra field(L字节)+ 头CRC(2字节)才能到达压缩数据。但是,我们不知道L的值,所以需要从文件中读取XLEN。 - **步骤2:使用dd或编程方式跳过多余的头** 由于手动操作复杂,我们可以尝试用以下方法: **方法A:使用gzip修复工具** ```bash # 尝试用gzip直接忽略头错误(可能无效) gzip -d < 损坏文件.tar.gz > 解压后的.tar ``` **方法B:手动剥离多余的头(需要知道L)** 我们可以用Python或C读取文件头,解析XLEN,然后跳过整个头(10+2+L+2字节)输出剩余部分(即原始压缩数据)。然后,将剩余部分作为gzip流解压(因为gzip允许多个成员,但通常tar.gz只有一个成员)。 下面是一个简单的Python脚本,用于剥离gzip头(适用于标志0x42): ```python import sys with open(sys.argv[1], 'rb') as f: # 读取固定头10字节 header = f.read(10) if len(header) < 10: print("File too short") sys.exit(1) # 解析flags(第4个字节,索引为3) flags = header[3] if flags != 0x42: # 确保是我们遇到的问题 print(f"Unexpected flags: {hex(flags)}") sys.exit(1) # 读取XLEN(2字节,小端) xlen_bytes = f.read(2) xlen = xlen_bytes[0] + (xlen_bytes[1] << 8) # 跳过extra field(xlen字节) f.read(xlen) # 跳过头CRC16(2字节) f.read(2) # 读取剩余数据(压缩数据) compressed_data = f.read() # 将剩余数据写入新文件(这是一个有效的gzip流吗?) with open(sys.argv[2], 'wb') as out: out.write(compressed_data) ``` 运行脚本: ```bash python3 strip_gzip_header.py 损坏文件.tar.gz 修复后.tar.gz ``` 然后尝试解压修复后的文件: ```bash tar -zxf 修复后.tar.gz ``` 注意:这种方法假设文件头之后只有一个gzip成员(通常tar.gz只有一个)。如果原始文件有多个成员,可能需要更复杂的处理。 - **方法C:使用dd跳过固定字节(如果知道extra field长度)** 如果每次传输添加的extra field长度固定(比如10字节),则可以直接跳过: ```bash # 假设extra field长度为10,则跳过10(固定头)+2(XLEN)+10(extra field)+2(CRC16)=24字节 dd if=损坏文件.tar.gz of=修复后.tar.gz bs=1 skip=24 ``` 然后解压修复后文件。但这种方法需要提前知道extra field的长度。 ### 4. **发送方压缩时避免特殊标志** 在发送方压缩时,使用gzip的`-n`选项避免保存原文件名和时间戳,确保不生成额外字段: ```bash # 使用gzip单独压缩(不推荐,因为通常用tar -z) gzip -n -c myfile.tar > myfile.tar.gz # 或者使用tar直接创建 tar -cf - mydir | gzip -n > myfile.tar.gz ``` 这样生成的文件头会更简单,减少传输中出错的可能性。 ### 5. **替代方案:使用其他压缩格式** 如果问题持续,考虑使用其他格式(如`.tar.bz2`或`.tar.xz`): ```bash # 压缩 tar -jcf myfile.tar.bz2 mydir # 传输后解压 tar -jxf myfile.tar.bz2 ``` ### 总结步骤 1. **优先重新使用可靠协议传输**(如SCP)。 2. **检查网络设备**,确保没有修改数据包。 3. **在接收端修复文件**: - 使用Python脚本剥离多余的gzip头(推荐,因为能动态处理extra field长度)。 - 或用dd跳过固定字节(如果extra field长度已知)。 4. **发送方压缩时使用`gzip -n`**避免额外字段。 5. **换用其他压缩格式**(如bz2)。 ### 相关问题(§§相关问题§§) 1. 如何用Python解析gzip文件头? 2. 网络传输中如何避免中间设备修改数据? 3. tar.gz和tar.bz2的优缺点比较? 4. 如何检测和修复损坏的gzip文件? 希望这些方法能解决您的问题!如果修复后文件仍无法解压,可能需要重新传输或检查源文件。</think>### 解决TCP传输中tar.gz被添加CRC校验导致解压失败的问题 您遇到的核心问题是:**TCP传输过程中某些网络设备或中间件自动添加了CRC校验(标志0x42),导致标准gzip工具无法识别修改后的文件头**。这属于网络传输层对数据包的非常规修改。以下是系统化的解决方案: --- ### 一、根本原因分析 1. **标志0x42的含义**: - `0x42`(二进制`01000010`)表示gzip头包含: - **0x02位**:头部CRC16校验(Header CRC) - **0x40位**:额外字段(Extra field) - 标准gzip工具(如Linux默认版本)不支持这种修改后的头结构[^1] 2. **问题触发点**: - 网络设备(如代理、负载均衡器)在传输中注入校验字段 - TCP应用未正确处理数据边界,导致尾部数据被解释为头字段 - 传输工具(如自定义socket程序)添加了额外校验 --- ### 二、解决方案(逐步操作) #### 方法1:接收端手动修复文件头(推荐) ```bash # 步骤1:跳过被添加的12字节校验字段(10字节extra field + 2字节CRC) dd if=损坏文件.tar.gz of=修复后.tar.gz bs=1 skip=12 # 步骤2:解压修复后的文件 tar -zxvf 修复后.tar.gz ``` **原理**:`0x42`标志通常添加12字节头字段,跳过即可恢复标准gzip格式[^1]。 #### 方法2:发送端禁用gzip头元数据 ```bash # 压缩时使用 -n 选项忽略原始文件名和时间戳 tar -cf - 目录 | gzip -n > 安全压缩包.tar.gz # 传输后再解压(此时无额外字段) tar -zxvf 安全压缩包.tar.gz ``` **优势**:生成最小化gzip头,避免被中间设备篡改[^1]。 #### 方法3:网络层规避措施 ```bash # 使用base64编码传输(避免二进制被修改) 发送端:base64 源文件.tar.gz > 传输文件.txt 接收端:base64 -d 传输文件.txt > 还原.tar.gz # 或使用rsync代替原始TCP rsync -avz 源文件.tar.gz user@remote:/path/ ``` #### 方法4:强制解压工具 ```bash # 使用zcat忽略头错误(可能恢复部分数据) zcat 损坏文件.tar.gz > 临时.tar tar -xvf 临时.tar # 或使用pigz(多线程gzip) pigz -dc 损坏文件.tar.gz | tar -xvf - ``` --- ### 三、预防措施 1. **传输协议**: ```bash # 使用SSH加密隧道(避免中间设备干预) scp -C 源文件.tar.gz user@host:/path/ ``` 2. **压缩参数**: ```bash # 始终使用gzip -n(不保存原始属性) gzip -n 文件.tar ``` 3. **完整性验证**: ```bash # 发送方生成校验码 sha256sum 源文件.tar.gz > checksum.txt # 接收方验证 sha256sum -c checksum.txt ``` 4. **网络设备检查**: - 禁用代理的"数据优化"功能 - 关闭负载均衡器的`TCP checksum offloading` --- ### 四、技术验证 ```mermaid graph LR A[原始tar.gz] --> B{TCP传输} B --> C[中间设备添加CRC] C --> D[损坏文件.tar.gz] D --> E[dd跳过12字节] E --> F[标准gzip格式] F --> G[成功解压] ``` --- ### 相关问题(
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值