一文读懂网络报问中的检验和(checksum) 您所在的位置:网站首页 矩阵相加怎么算出来的 一文读懂网络报问中的检验和(checksum)

一文读懂网络报问中的检验和(checksum)

2024-07-10 13:08| 来源: 网络整理| 查看: 265

如何求解网络报文中的checksum?

最近在学习计算机网络,在运输层和网络层部分存在各种协议TCP、UDP、IP、ICMP等等,而在这些报文中都存在一个公共的字段——检验和(checksum)。接下来,我将从什么是检验和、检验和怎么算、检验和计算示例、python代码计算检验和这几个部分详细介绍。

什么是检验和?

检验和是存在于各种报文中的一个字段,它存在的目的是验证报文在网络传输过程中的完整性(有的数据可能在链路传输时发生0-1数据翻转,从而导致报文出错)。因此,在报文的发送端,会根据报文中的首部或数据来计算一个检验和(IP报文的检验和只对首部进行计算,ICMP报文对报文首部和数据都进行计算),然后一旦接收端接受到相应报文,接收端也会对报文的首部或数据进行一次检验和计算,如果接收端算出来的检验和和发送端发送的不一样,那么对不起,接收端认为报文在传输过程中出了错,于是就丢掉该报文。

算法归纳

待检验部分从头开始,每16比特进行一次加法计算(如果最后有8位剩余,最后加上这8位),这样最终计算出来的和进行一次反码运算,就是检验和。 注意:如果求和过程中遇到了任何溢出,都进行回卷(即加回到最低位)

example

在这里插入图片描述

IP报文各字段

看完上面还迷迷糊糊的?没关系,在这里,就以IP报文为例,介绍更多的细节。首先,还是先把IP报文的各个字段信息回顾一下,如下图。如果你看到这个,有些字段忘记了它的意思,就百度回忆一下吧,这里我就不多说了。 在这里插入图片描述

IP首部检验和示例

现在假设有一个IP报文的首部如下所示(都是16进制数): 4500 003c 1c46 4000 4006 b1e6 ac10 0a63 ac10 0a0c

ok,我们将这个报文的各个字段一一来匹配一下

45 —— 对应IP首部前8位,4是version字段,表示IPV4,5是首部长度字段,但注意,首部长度是以每4个字节为1个单位的,所以这里就是5*4=20个字节 (这也说明IP报文首部的option字段和padding字段没用上)00 —— 对应服务类型(TOS,type of service)字段,00表明是正常操作003C —— 对应total length字段,说明改IP报文首部加数据段一共是60字节(也就是说,数据段部分占了40字节)1C46 —— 对应报文标识符字段4000 —— 对应flags和fragment offset字段,其中flag字段占3位,分片偏移占13位40 —— 对应TTL字段(Time to live),表明该报文可以经过40跳(hops)06 —— 对应IP报文封装的上层协议代码,这里是6,表明是TCP报文b1e6 —— 这就是发送端即将求出来的检验和ac10 0a63 —— 对应IP报文的源IP地址ac10 0a0c —— 对应IP报文的目的IP地址 发送端

Alright ! 终于可以开始计算了。 : )

说明:在计算检验和字段之前,我们先把检验和的16位全部置0。

我们现在把16进制数全部转为二进制,如下:

4500 -> 0100010100000000 003c -> 0000000000111100 1c46 -> 0001110001000110 4000 -> 0100000000000000 4006 -> 0100000000000110 0000 -> 0000000000000000 // 先全部置零,最后再把算出来的结果附加上 ac10 -> 1010110000010000 0a63 -> 0000101001100011 ac10 -> 1010110000010000 0a0c -> 0000101000001100

然后我们每16位进行一次加法运算:

4500 -> 0100010100000000 003c -> 0000000000111100 453C -> 0100010100111100 // 第一次计算结果 453C -> 0100010100111100 // 第一次计算结果 加 后16位 1c46 -> 0001110001000110 6182 -> 0110000110000010 // 第二次计算结果 6182 -> 0110000110000010 // 第二次计算结果 加 后16位 4000 -> 0100000000000000 A182 -> 1010000110000010 // 第三次计算结果 A182 -> 1010000110000010 // 第三次计算结果 加 后16位 4006 -> 0100000000000110 E188 -> 1110000110001000 E188 -> 1110000110001000 AC10 -> 1010110000010000 18D98 -> 11000110110011000 // 这里产生了一次溢出,根据回卷规则,把溢出位加到最后 18D98 -> 11000110110011000 8D99 -> 1000110110011001 // 进行类似16位加法。。。就不再重述了 8D99 -> 1000110110011001 0A63 -> 0000101001100011 97FC -> 1001011111111100 97FC -> 1001011111111100 AC10 -> 1010110000010000 1440C -> 10100010000001100 // 由产生了进位,继续回卷 1440C -> 10100010000001100 440D -> 0100010000001101 440D -> 0100010000001101 0A0C -> 0000101000001100 4E19 -> 0100111000011001

Well,终于加完了,别急还没完!!!还要求一次反码,别忘了哈~~

4E19 -> 0100111000011001 B1E6 ->1011000111100110 // 检验和

好了,这样我们再把b1e6这个检验和放进到IP报文的checksum字段,检验的工作也就此完成。

接收端

接收端就比较简单了,把所有的二进制位每16位进行一次加法,最后求一次补码(同样也要溢出回卷),如果结果全部是1,那就稳了,没出错;只要有一位是0,那就说明出现了错误。

Python实现

看完以上,你肯定懂了是怎么算的,但是代码实现可能还有点困难,这里特别感谢JamesF. Kurose ——《计算机网络:自顶向下方法》的作者在书中附带的资源和代码,以下代码来自书中编程实验的ICMPping程序。

具体的代码解析我注释好了,大家可以看看。

def checksum(str): csum = 0 # 校验和 (一个32位十进制数,因为每16位相加时可能会产生进位(即溢出),这些溢出将会被回卷) # 奇偶控制,如果总长的字节数为奇数时,肯定最后一个字节要单独相加(求校验和时是每16位一加) countTo = (len(str) // 2) * 2 count = 0 while count < countTo: # ord()函数返回一个字符的ASCII码 # 取两个字节,第二个字节放在16位的高位,第一个字节放在16位的地位 thisVal = (str[count + 1] > 16) + (csum & 0xffff) # 如果还产生了溢出,再操作一次 csum = csum + (csum >> 16) # 求反码 answer = ~csum answer = answer & 0xffff # 这里进行字节序大小端转换,因为网络字节序是大端模式 answer = answer >> 8 | (answer


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有