如何计算IP首部校验和Header CheckSum(计算详解、代码解析、例子)

这篇具有很好参考价值的文章主要介绍了如何计算IP首部校验和Header CheckSum(计算详解、代码解析、例子)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言:本文灵感来自于上课的时候老师提出的问题。正是由于老师刨根问底地追问,才让我写下了这篇文章。

目录

什么是首部校验和?

首部校验和计算的过程

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.步骤

首部校验和的计算过程包括以下几个步骤:

  1. 将校验和字段的值初始化为0,作为校验和的累加器。
  2. 将首部中的每一段数据按照一定的单位(通常是16位)进行分组。
  3. 依次将这些数据段的值累加到校验和累加器中。
  4. 如果累加和的结果超过了该数据段所能表示的最大值,需要进行进位操作。
  5. 对累加和的最终结果进行取反,得到校验和的值。

还是很迷糊对不对?让我再来拆解一下。

1. IP数据报格式

首先,我们要了解IP数据报的格式。

ip首部校验和,tcp/ip,网络,服务器,c语言,算法

如图,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首部校验和,tcp/ip,网络,服务器,c语言,算法

通过抓包工具/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)

ip首部校验和,tcp/ip,网络,服务器,c语言,算法

我在此把二进制和十六进制都写了,计算的时候我按照16进制来。

首部校验和=ffff-(4500+003c+03cd+0000+4001+c0a8+0118+c0a8+0101)=0xf38a

与图片上显示出都首部校验和0xf38a一致。

是不是很简单?

非也,接下来要考虑到一些情况。

3.如何处理数据段不是单位的整数倍的情况

通常情况下,首部中的数据段是按照16位或32位进行划分的,而数据接收时可能会出现数据段不是单位的整数倍的情况。为了处理这种情况,我们可以采取以下方式:

  1. 首先,按照单位(如16位或32位)累加所有完整的数据段。
  2. 接下来,对于剩余不完整的数据段,将其视为一个字节的数据。
  3. 将这个字节数据累加到校验和累加器中。

4.处理进位的情况

在计算校验和的过程中,有可能会出现进位的情况。如果累加和的结果超过了对应数据段所能表示的最大值,就需要进行进位操作。

处理进位的方法是:

  1. 将累加和右移一位,将进位的位数加到累加和中。
  2. 将累加和与进位的位数进行按位与操作,将进位带到低位,继续进行累加。
  3. 如果仍然有进位,重复以上步骤,直到没有进位为止。

代码实现

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校验算法是一种基于二进制多项式除法的校验方法,它可以检测出多种数据传输错误,如单比特差错、双比特差错、突发错误等。在计算机网络、通信、存储等领域中广泛应用。

WireShark

WireShark是一款流行的网络封包分析工具,可以截取各种网络数据包,并显示数据包详细信息。它可以用于网络故障排查、网络安全分析、网络协议开发等方面。WireShark提供了丰富的过滤器功能,可以根据协议、端口、主机名、数据包内容等多种条件进行过滤,方便用户快速定位需要分析的数据包。同时,WireShark还提供了多种统计和图形化分析工具,可以帮助用户更好地理解网络数据流量和协议行为。如果你需要进行网络数据包分析,WireShark是一个非常好的选择。文章来源地址https://www.toymoban.com/news/detail-754180.html

到了这里,关于如何计算IP首部校验和Header CheckSum(计算详解、代码解析、例子)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • CAPL计算TCP校验和Checksum

    随着全球智能电动汽车的普及,车载以太网也越来越多应用到汽车网络中,而TCP协议也是常用的协议,TCP校验和计算方法在网上的资料也比较多,如:Python、Java等语言的计算方法,但是在车载行业使用CAPL语言较多,这方面资料相对较少,故本文主要分享CAPL语言如何计算TCP校

    2024年02月10日
    浏览(24)
  • 计算机网络-传输层(UDP协议报文格式,伪首部,UDP校验过程)

    UDP只在IP数据报服务之上增加了很少功能,即复用分用和差错检测功能。 UDP的主要特点: UDP是无连接的,减少开销和发送数据之前的时延。 UDP使用最大努力交付,即不保证可靠交付。 UDP是面向报文的,适合一次性传输少量数据的网终应用。 应用层给UDP多长的报文,UDP就照样

    2023年04月25日
    浏览(34)
  • ip数据报计算首部检验和

    当我们在使用互联网进行数据传输时,数据可能会被篡改或者损坏。为了保证数据传输的可靠性和完整性,计算IP数据包首部检验和是一种非常重要的校验机制。本文将会介绍计算IP数据包首部检验和的方法。 IP数据包首部   首先,我们需要了解IP数据包首部的结构。IP数据包

    2024年02月15日
    浏览(22)
  • swarm节点间通信问题-关闭checksum校验和

    客户有n台redhat虚拟机,构建了一个swarm集群,服务起来后,发现不同节点间的服务,无法互相访问。经运维大佬排查是服务器的checksum校验是开启状态,关闭即可~ ethtool -k 内网网卡名称 | grep checksum 备注:上面的 备注① 和备注② 很重要,是这个脚本的开机启动顺序,如果配

    2024年01月16日
    浏览(26)
  • IP首部报文字段

    字段如下图所示 版本 表示 IP 协议的版本。通信双方使用的 IP 协议版本必须一致。目前广泛使用的IP协议版本号为 4,即 IPv4 首部长度 这个字段所表示数的单位是 32 位字长(1 个 32 位字长是 4 字节)。因此,当 IP 的首部长度为 1111 时(即十进制的 15),首部长度就达到 60 字

    2024年02月17日
    浏览(26)
  • IP、ICMP、TCP和UDP校验和计算

    一. 前言         计算网络数据包的校验和是机器自动完成,不需要手动计算。但是正因为如此,我们往往不会去深究校验和到底是怎么计算的,留下这一块盲区。虽然书上有大致介绍计算的方法,但是,“纸上得来终觉浅,绝知此事要躬行”,本文将详细演示IP、ICMP、TCP、

    2024年02月10日
    浏览(33)
  • Spring boot Websocket 添加授权校验(校验Header)

            最近需要用到websocket,并且确认是在登录成功的情况下才能连接,看了下,websocket 5.8以上已经支持校验了,但是由于我项目是spring boot 2.7.9,为了兼容,只能考虑通过在websocket 的header中带上验证信息,进行校验,详细如下 1.首先往spring boot pom 内加入 websocket的依赖

    2024年02月07日
    浏览(21)
  • checksum的算法和代码实现

    现在在一辆汽车上,有很多控制器,很多控制器之间的通讯需要通过CAN网络,通讯过程中数据的传输尤为重要,因为数据的交互之后往往伴随着相关的硬件会执行指令的请求。在这个过程中,数据的检验是非常有必要的,checksum就是用来校验数据的一致性,主要是输入和输出

    2024年02月14日
    浏览(32)
  • 【IP地址与子网掩码】如何计算网络地址、广播地址、地址范围、主机个数、子网数(附详解与习题)

    【 写在前面 】其实很多时候通过IP地址和子网掩码计算其网络地址、广播地址、可用IP,地址范围,主机数啥的,有些人不太清楚规则就只能瞎猜了,但是作为一个网络管理员还是一个基础常识的,这不因为最近备考网络管理员,所以我做了一个梳理,顺带出了一个习题给大

    2024年02月03日
    浏览(68)
  • 计算机网络的故事——HTTP首部

    在HTTP协议通信交互中使用的首部字段。不限于RFC2616中定义的47种首部字段,还有Cookie、setCookie和Content-Disposition等 HTTP 首部字段将定义成缓存代理和非缓存代理的行为,分成 2 种类型。端到端首部和逐跳首部

    2024年02月09日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包