1. 前言说明
2. 例子分析
3. 相关代码
4. 结果展示
5. 心得总结
在看完教材 5-50 题目的习题解答,稍微懂了一点二进制反码求和。手算总是觉得很容易出错,用程序帮我们计算,尽最大可能减少计算错误的发生。所以,我想用 Python 简易实现二进制反码求和计算 UDP 检验和的过程,顺便巩固和复习一些 Python 语法。
这里把题目和较详细解答过程直接贴在这里【思路 + 过程】
50. 把教材上的图 5-7 计算 UDP 检验和的例子自己具体演算一下,看是否能够得出书上的计算结果。
可以使用两种方法进行二进制反码求和的运算。一种方法是把这 14 行的 16 位数据一起从低位到高位逐位相加。另一种方法是把这 14 行的 16 位数据两行两行地相加(即二进制反码求和)
我们这里使用后一种方法,这里要相加 13 次。
第 1 行和 第 2 行相加,得 10100001 01111011
再和第 3 行相加,得 1 01001100 011111110。请注意,最左边(最高位)的 1 是进位得到的 1,这要和最低位相加。因此和第 3 行相加后,得 01001100 01111111。最低位的 1 就是由最高位的进位得到的。这叫做 “回卷”。
再和第 4 行相加,得 01011010 10001010。
再和第 5 行相加,得 01011010 10011011。
再和第 6 行相加,得 01011010 10101010。
再和第 7 行相加,得 01011110 11101001。
再和第 8 行相加,得 01011110 11110110。
再和第 9 行相加,得 01011111 00000101。
第 10 行是全 0,不用再计算相加。
再和第 11 行相加,得 10110011 01001010。
再和第 12 行相加,得 00000110 10011111。这里的最低位的 1 由最高位的进位回卷得到的。
再和第 13 行相加,得 01001111 11101101。
再和第 14 行相加,得 10010110 11101101。这就是二进制反码求和的结果。把这个结果求反码(1 换成 0 而 0 换成 1),得出:01101001 00010010。这就是应当写在检验和字段的数。和书上给出的结果是一致的。
UDP 用户数据报传送到接收端后,再进行检验和计算。这就是把收到的 UDP 用户数据报连同伪首部(以及可能的填充全零字节)一起,按二进制反码求这些 16 位字的和。当无差错时其结果应当全 1。否则就表明有差错出现,接收方就应丢弃这个 UDP 用户数据报(也可以上交应用层,但附上出现差错的警告)。
简易实现:
def checkBits(raw_data, bits):
# 检查原来的数据是否满足 bits 位
for (a, b) in enumerate(raw_data):
if len(b) != bits:
print("NO.{}: {}".format(a+1, b))
return False
return True
def format_print(string, bits):
# 对按bits字符串切片,加空格
length = len(string)
new_list = []
for i in range(bits, length+1, bits):
new_list.append(string[i-bits:i])
remain = length % bits
if remain != 0:
new_list.append(string[-remain:])
return ' '.join(new_list)
class Binary_complement_sum():
def __init__(self, raw_bits, bits):
self.raw_bits = raw_bits
self.bits = bits
self.total = ''
self.inv_dict = {'0': '1',
'1': '0'}
def calculate(self):
# 用二进制反码求和的方法加起来
total = self.raw_bits[0]
for i in self.raw_bits[1:]:
total = str(bin(int(total, 2) + int(i, 2)))[2:]
if len(total) > self.bits:
total = str(bin(int(total[-self.bits:], 2) + 1))[2:]
self.total = total
return total
def inverse(self):
# 求它的反码
inv_code = ''
for i in self.total:
inv_code += self.inv_dict[i]
return inv_code
if __name__ == '__main__':
raw_data = ['1001100100010011',
'0000100001101000',
'1010101100000011',
'0000111000001011',
'0000000000010001',
'0000000000001111',
'0000010000111111',
'0000000000001101',
'0000000000001111',
'0000000000000000',
'0101010001000101',
'0101001101010100',
'0100100101001110',
'0100011100000000']
bits = 16
# 检查位数是否满足 bit 位
if checkBits(raw_data, bits):
bin_com_sum = Binary_complement_sum(raw_data, bits)
total = bin_com_sum.calculate()
inv_code = bin_com_sum.inverse()
print("二进制反码运算求和:{}".format(format_print(total, 8)))
print("将得出的结果求反码:{}".format(format_print(inv_code, 8)))
else:
print("请检查原始数据是否输入正确!")
①
raw_data = ['1001100100010011',
'0000100001101000',
'1010101100000011',
'0000111000001011',
'0000000000010001',
'0000000000001111',
'0000010000111111',
'0000000000001101',
'0000000000001111',
'0000000000000000',
'0101010001000101',
'0101001101010100',
'0100100101001110',
'0100011100000000']
结果:
# 上面例子的检验
二进制反码运算求和:10010110 11101101
将得出的结果求反码:01101001 00010010
>>>
②
raw_data = ['1001100100010010',
'0000100001101001',
'1010101100000010',
'0000111000001010',
'0000000000010001',
'0000000000001111',
'0000010000111111',
'0000000000001101',
'0000000000001111',
'0000000000000000',
'0101010001000101',
'0101001101010100',
'0100100101001111',
'0100011100000000']
结果:
二进制反码运算求和:10010110 11101100
将得出的结果求反码:01101001 00010011
>>>
例题来自:二进制反码求和举例
实验的例子太少,导致没办法验证代码的可靠性。但是用教材上的例子实验,结果表明没有问题。通过对题目解答的了解和阅读,按二进制反码求和开始懂一些了。边学变练,记得才牢。好记性不如烂笔头。ヾ(◍°∇°◍)ノ゙ 加油吧
Fin.