二进制反码求和运算
(2019年2月19日注:这篇文章原先发在自己github那边的博客,时间是2016年7月12日)
周四要给工作室的小朋友们继续培训计算机网络,要讲的内容是传输层,于是今天就在准备相应的材料,重新看回谢希仁老师的课本过程中又加深了一点理解,然后看到了当时碰到的第一个难点,UDP协议的校验和的计算。
其实本质上来说这个计算原理还是不难的,就是一个二进制反码求和运算,具体来说就是:
其中10中的1加到了下一列去,如果是最高列的1+1,那么得到的10留下0,1移到最低列,与最低位再做一次二进制加法即可。
在谢老师的这本书里,讲到的是一个15字节的UDP数据在发送方怎么进行数据的检验,然后列出了一个二进制的竖式并给出一个结果,然而并没有讲述是怎么计算出来的。经过我不断的努力,终于把二进制计算的过程整个写出来了。之前在数计院上课的时候,老师讲过一个较为之简单的十六进制计算法,对比之下确实是简单很多。好了,先上图。
谢老师在课本里面给出的题目是这样子的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | 二进制版 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。
好了这次先针对这个特定的问题提出了解决方案,有时间要好好整理下关于计算机的原码、反码和补码的知识。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理