在进行网络编程时,校验和用来保证数据接收的完整性,这里详细讲解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);
}