您的位置:首页 > 其它

icmp校验和算法详解

2011-04-02 10:58 204 查看

在进行网络编程时,校验和用来保证数据接收的完整性,这里详细讲解icmp校验和的算法.tcp,udp,ip等协议校验和的算法与icmp协议相同(测试环境为vs2005/winxp).

icmp头部定义如下:
#pragma pack(1)
struct ICMPHeader
{
 unsigned char icmp_type;       //icmp service type, 8 echo request, 0 echo reply
 unsigned char icmp_code;       //icmp header code
 unsigned short icmp_chksum;      //icmp header chksum
 unsigned short icmp_id;        //icmp packet identification
 unsigned short icmp_seq;       //icmp packet sequent
};
#pragma pack()
注意:#pragma pack(1)表示按照一字节对齐
下面用伪代码来描述计算校验和流程
char *pSendBuf = new char[sizeof (ICMPHeader) + nSendDataSize];
ICMPHeader *picmp_hdr = (ICMPHeader*)pSendBuf;
picmp_hdr->icmp_type = 8;
picmp_hdr->icmp_code = 0;
picmp_hdr->icmp_chksum = 0;
picmp_hdr->icmp_id = htons(1);
picmp_hdr->icmp_set = htons(1);

memset(pSendBuf+sizeof (ICMPHeader), ‘x’, nSendDataSize);

//不需要htons,详见rfc1071
picmp_hdr->icmp_chksum = checksum((unsigned short*)pSendBuf, sizeof (ICMPHeader) + nSendDataSize);

之后发送pSendBuf中的数据,长度为sizeof (ICMPHeader) + nSendDataSize;

char *pRecvBuf = new char[sizeof(ICMPHeader) + nSendDataSize];
当接收到数据报再对它进行校验和验证,假设接收到的icmp数据存在pRecvBuf中

ICMPHeader *picmp_hdr2 = (ICMPHeader*)pRecvBuf;

 //注意:验证数据的时候,不需要转化为主机字节序列,
 //因为校验和发送端是以网络字节序来计算的,接收到的字节序列已经是网络字节序
 //根据接收到的校验和进行验证

//不需要ntohs,详见rfc1071
//picmp_hdr2->checksum = ntohs(picmp_hdr2->checksum);

validatechecksum((unsigned short*)pRecvBuf, sizeof(ICMPHeader) + nSendDataSize);
如果validatechecksum为true表明数据接收没有错误.

checksum和validatechecksum两个函数的代码如下所示
//校验和求法:
//把数据报看成16比特整数序列(按网络字节顺序),
//对每个整数分别计算其二进制反码,然后相加
//再对结果计算一次二进制反码而求得
unsigned short checksum(unsigned short *buffer, int size)
{
 unsigned long cksum=0;
 while(size >1) {
  cksum+=*buffer++;
  size-=sizeof(unsigned short);
 }
 if(size) cksum+=*(unsigned short*)buffer;
 cksum=(cksum >> 16)+(cksum&0xffff);
 cksum+=(cksum >>16);
 return (unsigned short)(~cksum);
}

bool validatechecksum(unsigned short *buffer, int size)
{
 unsigned long cksum=0;
 while(size >1) {
  cksum+=*buffer++;
  size-=sizeof(unsigned short);
 }
 if(size) cksum+=*(unsigned short*)buffer;
 cksum=(cksum >> 16)+(cksum&0xffff);
 cksum+=(cksum >>16);
 return ((unsigned short)cksum == 0xFFFF);
}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: