(python)数据校验-CRC32校验

目录

前言

数据校验概念

CRC校验算法

CRC计算原理

CRC算法种类

代码实现CRC算法

python实现算法①

python实现算法②

总结


前言

        在二次开发eCan上位机应用时,遇到了采用CRC(全称是循环冗余校验)32算法校验文件传输完整性的场景,浅浅地记录一下使用心得.

数据校验概念

        数据在传输的过程中,会受到各种干扰的影响,如脉冲干扰,随机噪声干扰和人为干扰等,这会使数据产生差错。为了能够控制传输过程的差错,通信系统必须采用有效的检错方案。因此产生了数据校验。

        数据校验是为保证数据的完整性进行的一种验证操作。通常用一种指定的算法对原始数据计算出的一个校验值,接收方用同样的算法计算一次校验值,如果两次计算得到的检验值相同,则说明数据是完整的。

CRC校验算法

CRC计算原理

        被校验的数据 除以 多项式,得到的余数就是CRC数值。不过这里的除法是模2除法,也就是异或。多项式是通信中双方约定数,可以自己定义,不过目前有各个领域定义好的,可直接用。

CRC算法种类


{
    //CRC算法名称			宽度  多项式      初始值      结果异或值  输入反转    输出反转
    {"CRC4_ITU", 			4,     0x03,       0x00,       0x00,       E_TRUE,   E_TRUE},
    {"CRC5_EPC", 			5,     0x09,       0x09,       0x00,       E_FALSE,  E_FALSE},
    {"CRC5_ITU", 			5,     0x15,       0x00,       0x00,       E_TRUE,   E_TRUE},
    {"CRC5_USB", 			5,     0x05,       0x1F,       0x1F,       E_TRUE,   E_TRUE},
    {"CRC6_ITU", 			6,     0x03,       0x00,       0x00,       E_TRUE,   E_TRUE},
    {"CRC7_MMC", 			7,     0x09,       0x00,       0x00,       E_FALSE,  E_FALSE},
    {"CRC8", 				8,     0x07,       0x00,       0x00,       E_FALSE,  E_FALSE},
    {"CRC8_ITU", 			8,     0x07,       0x00,       0x55,       E_FALSE,  E_FALSE},
    {"CRC8_ROHC", 			8,     0x07,       0xFF,       0x00,       E_TRUE,   E_TRUE},
    {"CRC8_MAXIM", 			8,     0x31,       0x00,       0x00,       E_TRUE,   E_TRUE},
    {"CRC16_IBM", 			16,    0x8005,     0x0000,     0x0000,     E_TRUE,   E_TRUE},
    {"CRC16_MAXIM", 		16,    0x8005,     0x0000,     0xFFFF,     E_TRUE,   E_TRUE},
    {"CRC16_USB", 			16,    0x8005,     0xFFFF,     0xFFFF,     E_TRUE,   E_TRUE},
    {"CRC16_MODBUS",		16,    0x8005,     0xFFFF,     0x0000,     E_TRUE,   E_TRUE},
    {"CRC16_CCITT", 		16,    0x1021,     0x0000,     0x0000,     E_TRUE,   E_TRUE},
    {"CRC16_CCITT_FALSE",	16,    0x1021,     0xFFFF,     0x0000,     E_FALSE,  E_FALSE},
    {"CRC16_X25", 			16,    0x1021,     0xFFFF,     0xFFFF,     E_TRUE,   E_TRUE},
    {"CRC16_XMODEM", 		16,    0x1021,     0x0000,     0x0000,     E_FALSE,  E_FALSE},
    {"CRC16_DNP", 			16,    0x3D65,     0x0000,     0xFFFF,     E_TRUE,   E_TRUE},
    {"CRC32", 				32,    0x04C11DB7, 0xFFFFFFFF, 0xFFFFFFFF, E_TRUE,   E_TRUE},
    {"CRC32_MPEG2", 		32,    0x04C11DB7, 0xFFFFFFFF, 0x00000000, E_FALSE,  E_FALSE}
};

代码实现CRC算法

        要求:在这里,在IEEE 802.3 帧中采用的是CRC-32校验码,输出4个字节的校验码. 

        x32 + x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x + 1

        多项式按正常写法是0x04C11DB7 ,翻转则为 0xEDB88320

        通常的CRC算法在计算一个数据段的CRC值时,其CRC值是由求解每个数值的CRC值的和对CRC寄存器的值反复更新而得到的。

python实现算法①

binascii刚好有现成的可以直接调用.输入要求的是二进制,那就用binascii.a2b_hex将16进制的字符串转换成二进制.

import binascii

def crc2hex(crc):
    """
    crc : str 从hex文件或bin文件中获取的有效数据
           func a2b_hex 16进制字符串 -> 二进制
           func crc32 二进制 计算得到crc值 -> int
           最后和 0xffffffff 相乘得正值
    return str 4个字节
    """
    # return '%08x' % (binascii.crc32(binascii.a2b_hex(crc)) & 0xffffffff)
    # 增加一个 取反
    return '%08x' % (binascii.crc32(binascii.a2b_hex(crc)) & 0xffffffff ^ 0xffffffff)

python实现算法②

CRC- 32的算法的多项式是 0x04C11DB7 , 初始值默认是 0xFFFFFFFF.

有多项式和初始值,就可以事先构造表.这里用查表法来减少计算量,

import re
# 定义一个256个元素的全0数组
custom_crc32_table = [0 for x in range(0, 256)]

# 定义一个256个元素的全0数组
reversal_crc32_table = [0 for x in range(0, 256)]


# 一个8位数据加到16位累加器中去,只有累加器的高8位或低8位与数据相作用,
# 其结果仅有256种可能的组合值。
def generate_crc32_table():
    for i in range(256):
        c = i << 24
        for j in range(8):
            if (c & 0x80000000):
                c = (c << 1) ^ 0x04C11DB7
            else:
                c = c << 1
        custom_crc32_table[i] = c & 0xffffffff


def get_crc32_val(bytes_arr):
    length = len(bytes_arr)
    # print(f"data length {length}")
    if bytes_arr != None:
        crc = 0xffffffff
        for i in range(0, length):
            crc = (crc << 8) ^ custom_crc32_table[(getReverse(bytes_arr[i], 8) ^ (crc >> 24)) & 0xff]
    else:
        crc = 0xffffffff

    # - 返回计算的CRC值
    crc = getReverse(crc ^ 0xffffffff, 32)
    return crc

# 反转
def getReverse(tempData, byte_length):
    reverseData = 0
    for i in range(0, byte_length):
        reverseData += ((tempData >> i) & 1) << (byte_length - 1 - i)
    return reverseData

def reversal_init_crc32_table():
    for i in range(256):
        c = i

        for j in range(8):
            if (c & 0x00000001):
                c = (c >> 1) ^ 0xEDB88320
            else:
                c = c >> 1

        reversal_crc32_table[i] = c & 0xffffffff

def reversal_getCrc32(bytes_arr):
    length = len(bytes_arr)
    if bytes_arr != None:
        crc = 0xffffffff
        for i in range(0, length):
            crc = (crc >> 8) ^ reversal_crc32_table[(bytes_arr[i] ^ crc) & 0xff]
    else:
        crc = 0xffffffff

    crc = crc ^ 0xffffffff
    return crc

if __name__ == '__main__':
    import struct
    import zlib
    import binascii

    s = struct.pack('>i', 400)
    print('当前CRC输入初始值:', (s, type(s)))
    test = binascii.crc32(s) & 0xffffffff
    print('算出来的CRC值:', '0x' + "{:0>8s}".format(str('%x' % test)))
    test = zlib.crc32(s) & 0xffffffff
    print('算出来的CRC值:', '0x' + "{:0>8s}".format(str('%x' % test)))

    buf_s = [0x00, 0x00, 0x01, 0x90]

    generate_crc32_table()
    crc_stm = get_crc32_val(bytearray(buf_s)) & 0xffffffff
    print('算出来的CRC值:', '0x' + "{:0>8s}".format(str('%x' % crc_stm)))

    reversal_init_crc32_table()
    crc_stm = reversal_getCrc32(bytearray(buf_s)) & 0xffffffff
    print('反转算出来的CRC值:', '0x' + "{:0>8s}".format(str('%x' % crc_stm)))


    """
    当前CRC输入初始值: (b'\x00\x00\x01\x90', )
    算出来的CRC值: 0xc8507d19
    算出来的CRC值: 0xc8507d19    
    算出来的CRC值: 0xc8507d19
    反转算出来的CRC值: 0xc8507d19
    
    """



总结

        在数据传输前,CRC校验得到一个4字节的校验码.接收方对获取的有效数据进行同样的校验,若校验码一致,说明传输的数据是完整的.

        CRC算法的种类多样,在算法上的差别在于多项式和初始值,这两个也可以自行定义.

你可能感兴趣的:(数据处理,python,开发语言)