前言:本文灵感来自于上课的时候老师提出的问题。正是由于老师刨根问底地追问,才让我写下了这篇文章。
目录
什么是首部校验和?
首部校验和计算的过程
0.步骤
1. IP数据报格式
2. 例子
3.如何处理数据段不是单位的整数倍的情况
4.处理进位的情况
代码实现
ed1
ed2
代码解释
1. if(size) cksum += *(UCHAR*)buffer;
2. cksum = (cksum>>16) + (cksum&0xffff);
扩展
CRC
WireShark
什么是首部校验和?
首部校验和是在网络通信中常用的一种校验方法,用于验证数据包在传输过程中是否出现了错误或损坏。通常应用于网络层协议(如IP协议)的首部中。
首部校验和计算的过程
我先摘录一段话:
IP首部的检验和不采用复杂的CRC检验码而采用下面的简单计算方法:
在发送方,先把IP数据报首部划分为许多16位字的序列,并把检验和字段置零。用反码算术运算把所有16位字相加后,将得到的和的反码写入检验和字段。
接收方收到数据报后,将首部的所有16位字再使用反码算术运算相加一次。将得到的和取反码,即得出接收方检验和的计算结果。
若首部未发生任何变化,则此结果必为0,于是就保留这个数据报。否则即认为出差错。
看懂了吗?是不是很迷糊?
我来解释一下。
0.步骤
首部校验和的计算过程包括以下几个步骤:
- 将校验和字段的值初始化为0,作为校验和的累加器。
- 将首部中的每一段数据按照一定的单位(通常是16位)进行分组。
- 依次将这些数据段的值累加到校验和累加器中。
- 如果累加和的结果超过了该数据段所能表示的最大值,需要进行进位操作。
- 对累加和的最终结果进行取反,得到校验和的值。
还是很迷糊对不对?让我再来拆解一下。
1. IP数据报格式
首先,我们要了解IP数据报的格式。
如图,IP数据报以上部分组成,而计算首部校验和则需要用到以下12个字段。
没错,就是固定部分的所有内容(20字节)。
它包含:
- 版本(Version)
- 首部长度(Header Length)
- 区分服务(Differentiated Service Field)
- 总长度(Total Length)
- 标识 (Identification)
- 标志 (Flags)
- 片偏移(Fragment Offset)
- 生存时间 (Time to Live)
- 协议(Protocol)
- 首部检验和(Header CheckSum)
- 源地址(Source Address)
- 目的地址 (Destination Address)
知道了这些东西,我们才能计算首部校验和。
2. 例子
用WireShark进行抓包,得到以下数据:
通过抓包工具/IP数据报的结构可知:
(1)版本 = 4
(2)首部长度 = 5
(3)区分服务 =0(0x00)
(4)总长度 = 60(0x003c)
(5)标识 = 0973 (0x03cd)
(6)标志 = 0
(7)片偏移 = 0
(8)生存时间 = 64(0x40)
(9)协议 = 1
(10)首部检验和 = 0xf38a
(11)源地址 = 192.168.1.24(c0 a8 01 18)
(12)目的地址 = 192.168.1.1(c0 a8 01 01)
我在此把二进制和十六进制都写了,计算的时候我按照16进制来。
首部校验和=ffff-(4500+003c+03cd+0000+4001+c0a8+0118+c0a8+0101)=0xf38a
与图片上显示出都首部校验和0xf38a一致。
是不是很简单?
非也,接下来要考虑到一些情况。
3.如何处理数据段不是单位的整数倍的情况
通常情况下,首部中的数据段是按照16位或32位进行划分的,而数据接收时可能会出现数据段不是单位的整数倍的情况。为了处理这种情况,我们可以采取以下方式:
- 首先,按照单位(如16位或32位)累加所有完整的数据段。
- 接下来,对于剩余不完整的数据段,将其视为一个字节的数据。
- 将这个字节数据累加到校验和累加器中。
4.处理进位的情况
在计算校验和的过程中,有可能会出现进位的情况。如果累加和的结果超过了对应数据段所能表示的最大值,就需要进行进位操作。
处理进位的方法是:
- 将累加和右移一位,将进位的位数加到累加和中。
- 将累加和与进位的位数进行按位与操作,将进位带到低位,继续进行累加。
- 如果仍然有进位,重复以上步骤,直到没有进位为止。
代码实现
ed1
USHORT checksum(USHORT* buffer, int size)
{
unsigned long cksum = 0;
while(size>1)
{
cksum += *buffer++;/*
这里实质上就是
checkSum+=*pBuf;
*pBuf++;
*/
size -= sizeof(USHORT);
}
if(size)
{
cksum += *(UCHAR*)buffer;
}
/*对于接下来两行,可以写个通用的程序,这样如果产生了多于两次(三次及以上)进位时也能用,但是一般来说,进位不会超过2次
while(ckSum>>16){
cksum = (cksum>>16) + (cksum&0xffff);
}
*/
cksum = (cksum>>16) + (cksum&0xffff); //这段代码是进行16位校验和的溢出处理
cksum += (cksum>>16);
return (USHORT)(~cksum);
}
ed2
上面代码的改版,思路来源于我的老师提出的问题:如果把指针的类型从USHORT改为UCHAR该怎么办?
USHORT checksum(UCHAR* buffer, int size)
{
unsigned long cksum = 0;
while(size > 1)
{
cksum += *(USHORT*)buffer;
buffer += sizeof(USHORT);
size -= sizeof(USHORT);
}
if(size)
{
cksum += *(UCHAR*)buffer;
}
while (cksum >> 16)
{
cksum = (cksum & 0xffff) + (cksum >> 16);
}
return (USHORT)(~cksum);
}
代码解释
1. if(size) cksum += *(UCHAR*)buffer;
这段代码的作用是处理IP首部大小不是2的整数倍时的剩余字节的情况。
if(size)表示如果剩余的字节数不为0(即size不为0),则执行相应的代码。
*(UCHAR*)buffer表示将指针buffer指向的地址强制转换为UCHAR类型的指针,也就是将指针buffer指向的地址视为一个字节的数据。
checkSum += *(UCHAR*)buffer表示将这个强制转换后的UCHAR类型的字节数据加到校验和checkSum中。
为什么不是*(UCHAR*)checkSum呢?因为checkSum此时是用来累加校验和的变量,并不代表具体的数据地址。实际上,checkSum存储的是累加后的校验和结果。
而这段代码的目的是处理IP首部中剩余的不足2个字节的情况,因此需要将buffer指向的具体地址(代表剩余的字节)当作一个字节的数据加入校验和中。
总结起来,代码*(UCHAR*)buffer的作用是将buffer指向的地址视为一个字节的数据,并将其加入到校验和checkSum中以进行处理。
为什么要强制类型转换?因为不做类型转换会加到不该加的东西,会多加一个字节的内容。
2. cksum = (cksum>>16) + (cksum&0xffff);
checkSum是一个无符号长整型,有可能会存在大于16位的计算,要进行高位溢出的处理。这时,要将checkSum右移16位,把高16位与低16位分开计算,并将结果相加。其中, >>表示右移操作,表示将checkSum向右移动16位。
(checkSum&0xffff)是为了保留checkSum的低16位,&运算符是位运算符,并且是按位与,(&&是逻辑与),将checkSum中的低16位与0xffff进行按位与操作,即得到checkSum的低16位。
一旦完成高16位与低16位的相加,如果还有进位,需要将进位的位数再加到checkSum中,以确保校验和的正确性。在这里可以用while循环来写。(如代码)
因此,这段代码的作用是为了保证IP首部校验和的正确性,处理了16位校验和的溢出,使用了位运算符>>和&,即右移和按位与。
扩展
CRC
CRC(Cyclic Redundancy Check)循环冗余校验,是一种数据传输检错技术。它通过在数据帧中添加校验位来检测数据传输过程中出现的差错。CRC校验算法是一种基于二进制多项式除法的校验方法,它可以检测出多种数据传输错误,如单比特差错、双比特差错、突发错误等。在计算机网络、通信、存储等领域中广泛应用。文章来源:https://www.toymoban.com/news/detail-754180.html
WireShark
WireShark是一款流行的网络封包分析工具,可以截取各种网络数据包,并显示数据包详细信息。它可以用于网络故障排查、网络安全分析、网络协议开发等方面。WireShark提供了丰富的过滤器功能,可以根据协议、端口、主机名、数据包内容等多种条件进行过滤,方便用户快速定位需要分析的数据包。同时,WireShark还提供了多种统计和图形化分析工具,可以帮助用户更好地理解网络数据流量和协议行为。如果你需要进行网络数据包分析,WireShark是一个非常好的选择。文章来源地址https://www.toymoban.com/news/detail-754180.html
到了这里,关于如何计算IP首部校验和Header CheckSum(计算详解、代码解析、例子)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!