基本概念
CRC全称是循环冗余校验(Cyclic Redundancy Check)。
在数据传输过程当中,不管传输系统的设计再怎么完美,差错总会存在,这种差错可能会致使在链路上传输的一个或者多个帧被破坏(出现比特差错,0变为1,或者1变为0),从而接受方接收到错误的数据。为尽可能提升接受方收到数据的正确率,在接收方接收数据以前须要对数据进行差错检测,当且仅当检测的结果为正确时接收方才真正收下数据。
CRC是一种用于校验通讯链路上数字传输准确性的计算方法(经过某种数学运算来创建数据位和校验位的约定关系)。发送方计算机使用某公式计算出被传送数据所含信息的一个值,并将此值附在被传送数据后,接收方计算机则对同一数据进行相同的计算,应该获得相同的结果。若是这两个CRC结果不一致,则说明发送中出现了差错,接收方计算机可要求发送方计算机从新发送该数据。
CRC是一种数据错误检查技术,是一种经常使用的检错码,但并不能用于自动纠错。数组
多项式
了解了CRC的基本概念,那么接下来就要知道多项式的概念了。
以这个IEEE802.3标准CRC32多项式为例:x32 + x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x+ 1
x32则对应32bit = 1, x26则对应26bit=1,得出一个值:(1<<32)|(1<<26)|(1<<23)|(1<<22)|…|(1<<1)|(1)=0x104C11DB7,对于CRC32取低32位,则=0x4C11DB7
通常是用这个值经过必定方法生成长度为256的码表,对于CRC32,表内每一个元素都为32bit。而后再用必定的方法查表最后得出CRC32值。测试
为何用查表这种方法呢?由于,世界上一共就256个字符,每装载一个就运算一遍,很浪费CPU资源,不如直接把每一个字符的CRC都算出来存入数组。所以,就有了CRC编码字符表。编码
接下来咱们看下最终实现代码:设计
# 定义一个256个元素的全0数组 custom_crc32_table = [0 for x in range(0,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 getCrc32(bytes_arr): length = len(bytes_arr) 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
咱们再来看看使用反转后的多项式(0xEDB88320)代码实现:code
# 定义一个256个元素的全0数组 reversal_crc32_table = [0 for x in range(0,256)] 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
测试代码:orm
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 = getCrc32(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)))
再看看最终的运行结果:ci
当前CRC输入初始值: (b'\x00\x00\x01\x90', <class 'bytes'>) 算出来的CRC值: 0xc8507d19 算出来的CRC值: 0xc8507d19 算出来的CRC值: 0xc8507d19 反转算出来的CRC值: 0xc8507d19