1.checksum是什么?
Checksum:【电脑】总和检验码,校验和。在数据处理和数据通信领域中,用于校验目的的一组数据项的和。这些数据项可以是数字或在计算检验总和过程中看作数字的其它字符串。
它通常是以十六进制为数制表示的形式
通常用来在通信中,尤其是远距离通信中保证数据的完整性和准确性
2.计算方法
1、 先将需要计算checksum数据中的checksum设为0;
2、 计算checksum的数据按2byte划分开来,每2byte组成一个16bit的值,如果最后有单个byte的数据,补一个byte的0组成2byte;
3、 将所有的16bit值累加到一个32bit的值中;
4、 将32bit值的高16bit与低16bit相加到一个新的32bit值中,若新的32bit值大于0Xffff,
再将新值的高16bit与低16bit相加;
5、 将上一步计算所得的16bit值按位取反(取反是取补码),即得到checksum值,存入数据的checksum字段即可。
3.算法实现的具体思路
参考的别的大佬的文章,数据拿过来
45 00 00 30 80 4c 40 00 80 06 b5 2e d3 43 11 7b cb 51 15 3d
1、第一步,checksum数据中的checksum=b52e设为0
遍历需要校验的数据,将checksum替换为0
45 00 00 30 80 4c 40 00 80 06 00 00 d3 43 11 7b cb 51 15 3d
2、第二步,求和
遍历求和,直接累加,最后输出的是一个int类型的十进制数
3、第三步,转十六进制,将进位添加到低位
python提供了直接将十进制数转为十六进制的内置函数:hex() 返回的是str型 例如:hex(12345)
4500+0030+804c+4000+8006+0000+d343+117b+cb51+153d=0x34ace
将进位(3)加到低16位(4ace)上:0003+4ace=4ad1
4、第四步,取反码
将4ad1取反得:checksum=b52e
4、使用python实现checksum算法
代码没有整理简化,
'''
自定义checksum算法实现
checksum:校验和
data:需要校验的数据
'''
import math
import numpy as np
class myCheckSum():
def __init__( self,checkSum,data=[] ):
self.checkSum=checkSum
self.data=data
self.hexadecimal={ 'a':10, 'b':11, 'c':12, 'd':13, 'e':14, 'f':15,
10:'a', 11:'b', 12:'c', 13:'d', 14:'e', 15:'f'} # 十六进制大于9的数
self.sumdata=0x0
#第一步,求和(遍历时遇到checksum,替换为0x0)
datas=self.sumCheckSum()
#第二步,将进位加到低位
cal=self.carryAddLow( len(self.sumdata),datas ) # len(self.sumdata)=5 cal=0x4ad1
#第三步,取补码
result=self.complementData(cal)
print('result:',result)
print('checksum:',checkSum) # checkSum: 46382
if result==checkSum:
print('True:正确')
else:
print('False:错误')
# 求和
def sumCheckSum(self):
dataLen=len(self.data)
for i in range(dataLen):
if self.data[i]==self.checkSum: # 找到checksum
self.sumdata+=0x0 # checksum替换为0x0来累加
else:
self.sumdata+=self.data[i]
#print( type( sel.SumData ) ) # 215758 <class 'int'> int型
self.sumdata=hex(self.sumdata)[2:] # '0x34ace' str类型 十六进制
datas=[]
for i in self.sumdata:
if i in ['a','b','c','d','e']:
datas.append( self.hexadecimal[i] )
else:
datas.append( int(i) )
#print( 'datas:',datas) # ['3','4','10','12','14']
return datas
# 取反 ,这里取反取的是补码 在python中 ~ 不能取到补码
def complementData(self,cal):
tenResult=int(cal,16)
twoResult=bin(tenResult)
calLen=len( cal[2:]) # 4
twoResultLen=len( twoResult[2:]) # 15
if calLen*4>twoResultLen:
subLen=calLen*4-twoResultLen # 1
twoResult='0'*subLen+twoResult[2:]
#print( 'twoResult:',twoResult ,'*type:',type(twoResult)) # twoResult: 0100101011010001 *type: <class 'str'>
reverseResult='0b'
for i in twoResult:
if i=='1':
reverseResult+='0'
else:
reverseResult+='1'
#print('reverseResult:',reverseResult) # reverseResult: 0b1011010100101110
#print(hex( eval(reverseResult) ) ) # 0xb52e
return eval(reverseResult) # 46382 十进制
# 进位加到低位 返回一个十六进制数
# 将32bit值的高16bit与低16bit相加到一个新的32bit值中,若新的32bit值大于0Xffff, 再将新值的高16bit与低16bit相加;
def carryAddLow(self,sumDataLen,datas): # sumDataLen=5 判断是否大于0Xffff,一种直接数值判断,另一种长度大于0Xffff的四位
bus,rem=divmod(sumDataLen,4) # 取bus商 rem余数
dualLists=[]
if rem != 0:
for i in range(bus+1): # 如果有余数 bus需要+1
dualLists.append([]) # dualLists=[ [], [], []]
if i==0: # 第一个list为 [0,0,0,3]
for j in range(4-rem):
dualLists[i].append(0)
for j in range(rem):
dualLists[i].append( datas[0] )
del datas[0]
else:
for j in range(4):
dualLists[i].append( datas[0] )
del datas[0]
else:
for i in range(bus):
dualLists.append([])
for j in range(4):
dualLists[i].append( datas[0] )
del datas[0]
#print( 'dualLists:',dualLists) # dualLists: [[0, 0, 0, 3], [4, 10, 12, 14]]
res=[0,0,0,0]
for i in range( len(dualLists)):
res=np.array(res)+np.array( dualLists[i] ) # 使用numpy中array把两个list相加
#print('res:',res) # res: [ 4 10 12 17] 到这里进位加到低位结束
result=[]
for i in range( len(res)-1,-1,-1 ): # 逆序遍历res
if res[i]>15: # 大于15的进位 小于等于的直接存了
result.append( res[i]%16 )
res[i-1]+=res[i]//15 ###################################################
else:
result.append( res[i] )
#print('result:',result)
data='0x'
for i in range( len(result)-1,-1,-1 ):
if result[i] in [10,11,12,13,14,15]:
data+=self.hexadecimal[ result[i] ]
else:
data+=str( result[i] )
#print('data:',data) # 4ad1
return data
验证一下
(1)反码求和
4500+0030+804c+4000+8006+b52e+d343+117b+cb51+153d=3fffc
0003+fffc=ffff
(2)取反码:~ffff=0 正确