登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

樱之花

叶散的时候,你明白欢聚;花谢的时候,你明白青春.

 
 
 

日志

 
 
关于我

分类中“我的实验室”是我在日常工作中的一些知识总结,有些写的比较匆忙,可能大家在阅读时会产生困扰,后期有时间我会重新整理编辑,谢谢大家的到访,您们的支持是我前进的动力!

IP包的校验和  

2012-09-10 14:47:40|  分类: MUD游戏开发 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

IP头结构

IPv4首部一般是20字节长。在以太网帧中,IPv4包首部紧跟着以太网帧首部,同时以太网帧首部中的协议类型值设置为080016 。 IPv4提供不同,大部分是很少用的选项,使得IPv4包首部最长可扩展到60字节(总是4个字节4个字节的扩展)
0 4 8 12 16 19 24 31
版本 首部长度 服务类型 长度
认证 标志 段偏移量
TTL 协议 校验和
源IP地址
目的IP地址
选项 ...

 IP包头字段说明

版本:4位,指定IP协议的版本号。

包头长度(IHL):4位,IP协议包头的长度,指明IPv4协议包头长度的字节数包含多少个32位。由于IPv4的包头可能包含可变数量的可选 项,所以这个字段可以用来确定IPv4数据报中数据部分的偏移位置。IPv4包头的最小长度是20个字节,因此IHL这个字段的最小值用十进制表示就是5 (5x4 = 20字节)。就是说,它表示的是包头的总字节数是4字节的倍数。

服务类型:定义IP协议包的处理方法,它包含如下子字段

        过程字段:3位,设置了数据包的重要性,取值越大数据越重要,取值范围为:0(正常)~ 7(网络控制)

        延迟字段:1位,取值:0(正常)、1(期特低的延迟)

        流量字段:1位,取值:0(正常)、1(期特高的流量)

        可靠性字段:1位,取值:0(正常)、1(期特高的可靠性)

        成本字段:1位,取值:0(正常)、1(期特最小成本)

        未使用:1位

长度:IP包的总长

认证:

标志:是一个3位的控制字段,包含:

        保留位:1位

        不分段位:1位,取值:0(允许数据报分段)、1(数据报不能分段)

        更多段位:1位,取值:0(数据包后面没有包,该包为最后的包)、1(数据包后面有更多的包)


段偏移量:当数据分组时,它和更多段位(MF, More fragments)进行连接,帮助目的主机将分段的包组合。

TTL:表示数据包在网络上生存多久,每通过一个路由器该值减一,为0时将被路由器丢弃。

协议:8位,这个字段定义了IP数据报的数据部分使用的协议类型。常用的协议及其十进制数值包括ICMP(1)、TCP(6)、UDP(17)。

校验和:16位,是IPv4数据报包头的校验和。

源IP地址:

目的IP地址:

ip 包的校验和

 

当发送 IP 包时,需要计算 IP 报头的校验和:

1    把校验和字段置为 0

2    IP 头部中的每 16bit 进行二进制求和;

3    如果和的高 16bit 不为 0 ,则将和的高 16bit 和低 16bit 反复相加,直到和的高 16bit 0 ,从而获得一个 16bit 的值;

4    将该 16bit 的值取反,存入校验和字段。

当接收 IP 包时,需要对报头进行确认,检查 IP 头是否有误,算法同上 2 3 步,然后判断取反的结果是否为 0 ,是则正确,否则有错。

  

算法:

SHORT checksum(USHORT* buffer, int size)

{

unsigned long cksum = 0;

while(size>1)

{

     cksum += *buffer++;

     size -= sizeof(USHORT);

}

if(size)

{

     cksum += *(UCHAR*)buffer;

}

cksum = (cksum>>16) + (cksum&0xffff);   // 将高 16bit 与低 16bit 相加

cksum += (cksum>>16);              // 将进位到高位的 16bit 与低 16bit 再相加

  

return (USHORT)(~cksum);

}

  

实例:

IP 头:   

               45 00     00 31

               89 F5     00 00

               6E 06     00 00 (校验字段)

               DE B7    45 5D        ->     222.183.69.93

               C0 A8    00 DC      ->     192.168.0.220

计算:     

     4500 + 0031 +89F5 + 0000 + 6e06+ 0000 + DEB7 + 455D + C0A8 + 00DC =3 22C4

     0003 + 22C4 = 22C7

      ~22C7 = DD38       -> 即为应填充的校验和

当接受到 IP 数据包时,要检查 IP 头是否正确,则对 IP 头进行检验,方法同上:

计算:

     4500 + 0031 +89F5 + 0000 + 6E06+ DD38 + DEB7 + 455D + C0A8 + 00DC =3 FFFC

     0003 + FFFC = FFFF

      ~FFFF = 00000      -> 正确

TCP 首部检验和与 IP 首部校验和的计算方法相同,在程序中使用同一个函数来计算。

需要注意的是,由于 TCP 首部中不包含源地址与目标地址等信息,为了保证 TCP 校验的有效性,在进行 TCP 校验和的计算时,需要增加一个 TCP 伪首部的校验和,定义如下:

struct

{

unsigned long saddr; // 源地址

unsigned long daddr; // 目的地址

char mbz;// 置空

char ptcl; // 协议类型

unsigned short tcpl; //TCP 长度

}psd_header;

然后我们将这两个字段复制到同一个缓冲区 SendBuf 中并计算 TCP 校验和:

memcpy(SendBuf,&psd_header,sizeof(psd_header));

memcpy(SendBuf+sizeof(psd_header),&tcp_header,sizeof(tcp_header));

tcp_header.th_sum=checksum((USHORT *)SendBuf,sizeof(psd_header)+sizeof(tcp_header));

IP校验和错误

通过这个校验值,接受方可以判断这个数据包是否完整接受,如果你经常出错,那可能链路存在比较严重的丢包和错包。
不过对于小带宽高负荷的internet线路来说这是难免的。
其他参考:http://bbs.chinaunix.net/thread-1504385-1-1.html
  评论这张
 
阅读(1242)| 评论(0)

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018