二进制反码求和运算
(2019年2月19日注:这篇文章原先发在自己github那边的博客,时间是2016年7月12日)
周四要给工作室的小朋友们继续培训计算机网络,要讲的内容是传输层,于是今天就在准备相应的材料,重新看回谢希仁老师的课本过程中又加深了一点理解,然后看到了当时碰到的第一个难点,UDP协议的校验和的计算。
其实本质上来说这个计算原理还是不难的,就是一个二进制反码求和运算,具体来说就是:$$0+0=0$$ $$1+0=0+1=1$$ $$1+1=10$$
其中10中的1加到了下一列去,如果是最高列的1+1,那么得到的10留下0,1移到最低列,与最低位再做一次二进制加法即可。
在谢老师的这本书里,讲到的是一个15字节的UDP数据在发送方怎么进行数据的检验,然后列出了一个二进制的竖式并给出一个结果,然而并没有讲述是怎么计算出来的。经过我不断的努力,终于把二进制计算的过程整个写出来了。之前在数计院上课的时候,老师讲过一个较为之简单的十六进制计算法,对比之下确实是简单很多。好了,先上图。
谢老师在课本里面给出的题目是这样子的。
二进制版 1001 1001 0001 0011 //伪首部源IP地址前16位 0000 1000 0110 1000 //伪首部源IP地址后16位 1010 1011 0000 0011 //伪首部目的IP地址前16位 0000 1110 0000 1011 //伪首部目的IP地址后16位 0000 0000 0001 0001 //伪首部UDP协议字段代表号17,前面8位是填充0 0000 0000 0000 1111 //伪首部UDP长度字段 0000 0100 0011 1111 //UDP头部源IP地址对应的进程端口号 0000 0000 0000 1101 //UDP头部目的IP地址对应的进程端口号 0000 0000 0000 1111 //UDP头部UDP长度字段 0000 0000 0000 0000 //UDP头部UDP检验和 0101 0100 0100 0101 //数据字段 0101 0011 0101 0100 //数据字段 0100 1001 0100 1110 //数据字段 0100 0111 0000 0000 //数据字段+填充0字段 十六进制版 9913 //伪首部源IP地址前16位 0868 //伪首部源IP地址后16位 AB03 //伪首部目的IP地址前16位 0E0B //伪首部目的IP地址后16位 0011 //伪首部UDP协议字段代表号17,前面8位是填充0 000F //伪首部UDP长度字段 043F //UDP头部源IP地址对应的进程端口号 000D //UDP头部目的IP地址对应的进程端口号 000F //UDP头部UDP长度字段 0000 //UDP头部UDP检验和 5445 //数据字段 5354 //数据字段 494E //数据字段 4700 //数据字段+填充0字段
在二进制版中,是不可以直接从右边第一列开始做竖式相加的,不要说十进制的竖式相加,二进制的竖式相加都做不到。
正确的做法是:
(1) 让第一行和第二行做二进制反码运算。
根据上述的规则,当碰到1+1=10时,在左邻侧一列下面写个小1(类似以前做十进制进位加法),然后侧列进行二进制反码运算得出一个数,如果没有进位,就继续与刚才的进位做二进制反码运算,如果有进位,则先把进位的小1写在相邻高侧列的下方,取个位来与其相加。有进位的只有1+1=10的情况,0不论加什么进位都不会有进位,而如果第一次计算没有进位时,只有产生1的情况下才会有进位,总而言之,对于每一列,都只会有至多一次的进位,所以不用担心进位会跨列的问题。这样子做要注意的就是不要写错数字了,比如我自己在写这张纸之前已经打过两次草稿了,然而还是会写错。
对于高位有1的情况,就是把1挪到最低位,再做一次二进制反码计算,本质来说就是取补码。
(2) 将第一行和第二行的结果与第三行做二进制反码计算,以此类推。
(3) 运算结果取反,得到校验和。
在十六进制版中,运算量会大大减小,主要的计算步骤如下:
(1) 从右边第一列开始,按照十进制来计算第一列的值。
在这里第一列算出来是107,写成8位二进制就是01101011。
(2) 根据算出来的结果分成两部分,左边的4位化成十进制,作为下一列进位时加的数,右边4位化成16进制,作为第一列的结果。
这里就是610B16,图片误算成D,6作为下一列运算时要加上的对象,B作为第一列的结果。
(3) 十进制计算第二列的结果,加上第一列得到的进位得到第二列的一个十进制数字,化为二进制,根据第二步来进行判断,依次类推。
在这里第二列算到的是24,加上6就是30,化为8位二进制就是00011110,也就是1E,第二列的结果为1,第三列的十进制进位为1。接着可以算到第三列的结果为6,十进制进位为4。
(4) 最高位算出最后的十进制结果后,化为二进制时,右边4位作为最终结果,左边4位移入下一列,用上一步得到的结果96EB,加上0010,得到最后结果,这里图片的最后一步写错了,不应该舍弃。
最后能得到结果为96ED。
(5) 结果取反,得到校验码。
校验码为6912。
好了这次先针对这个特定的问题提出了解决方案,有时间要好好整理下关于计算机的原码、反码和补码的知识。