基本概念
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