1、校验和是用于检测传输过程中可能产生的错误,将其置于数据后,随数据一同发送,接收端通过同样的算法进行检查,若正确就接受,错误就丢弃
校验和C源代码:
unsigned short checksum(unsigned char *buf,int len)
{
unsigned int sum=0; //1
unsigned short *cbuf; //2
cbuf=(unsigned short *)buf; //3
while(len>1) //4
{
sum+=*cbuf++;
len-=2;
}
if(len) //5
{
sum+=*(unsigned char *)cbuf;
}
while(sum>>16) //6
{
sum=(sum>>16)+(sum&0xffff);
}
return (~sum); //7
}
1.定义检验和变量,32位的 int型
2.定义接受的字符,16位的short int 型,因为校验和就是一个基于16位的反码计算原理,计算机制为1的补码,对称的系统,ffff和0000分别为-0和+0,afff和7ffff分别是-32767和+32767,这与我们平时遇到的2的补码机制不同
为什么要基于1的补码并进行反码求和机制?
因为考虑到大端和小端字节序的问题,在不同架构的处理器的保存方式不同,如果用常规的加法,接收端和发送端可能由于处理器架构不同会出现校验和的不同,但用反码求和,不管是大端还是小端,最终得到的结果都一样,不会影响到最终的校验和。
3.将8位的char类型转换成16位的short型
4.进行校验和的加法,都是基于16位的,每次进行16位移动
5.若len为奇数,要加上最后的8bit,也就是最后一个字节
6.将得到的校验和右移16位,这里是无符号的,也就是算术右移,后面一句也就是将sum的高16位和低16位做加法,这就是1的补码机制,最高位进位加到最低位。
7.最后返回校验和,是一个二进制的反码
2、checksum-8位和16位校验和代码示例
- // linux 系统编译通过
- // gcc filename.c -o filename
- // ./filename
- #include <stdlib.h>
- #include <stdio.h>
- unsigned char ip_hdr_8[] =
- {
- 0x45,0x00,
- 0x00,0x3c,
- 0x00,0x00,
- 0x00,0x00,
- 0x40,0x01,
- 0x00,0x00, // checksum
- 0xc0,0xa8,
- 0x01,0x25,
- 0xda,0x3c,
- 0x06,0x82
- };
- unsigned short ip_hdr_16[] =
- {
- 0x4500,
- 0x003c,
- 0x0000,
- 0x0000,
- 0x4001,
- 0x0000, // checksum
- 0xc0a8,
- 0x0125,
- 0xda3c,
- 0x0682
- };
- unsigned int checksum_8(unsigned int cksum, void *pBuffer, unsigned int size)
- {
- char num = 0;
- unsigned char *p = (unsigned char *)pBuffer;
- if ((NULL == pBuffer) || (0 == size))
- {
- return cksum;
- }
- while (size > 1)
- {
- cksum += ((unsigned short)p[num] << 8 & 0xff00) | (unsigned short)p[num + 1] & 0x00FF;
- size -= 2;
- num += 2;
- }
- if (size > 0)
- {
- cksum += ((unsigned short)p[num] << 8) & 0xFFFF;
- num += 1;
- }
- while (cksum >> 16)
- {
- cksum = (cksum & 0xFFFF) + (cksum >> 16);
- }
- return ~cksum;
- }
- unsigned short checksum_16(unsigned short *addr,int len)
- {
- unsigned short chksum;
- unsigned int sum = 0;
- while(len > 1)
- {
- sum += *addr++;
- len -= 2;
- }
- if(len == 1)
- sum += *(unsigned char*)addr;
- sum = (sum>>16) + (sum & 0xffff);
- sum += (sum>>16);
- chksum = ~sum;
- return (chksum);
- }
- void main()
- {
- unsigned short chksum;
- printf("--------------------------------------------\n");
- chksum = checksum_8(0,ip_hdr_8,sizeof(ip_hdr_8));
- printf("checksum_8 = 0x%04x \n",chksum);
- ip_hdr_8[10] = chksum >> 8;
- ip_hdr_8[11] = chksum & 0xff;
- chksum = checksum_8(0,ip_hdr_8,20);
- if(chksum)
- printf("Checksum_8 is incorrect! \n");
- else
- printf("Checksum_8 is correct! \n");
- printf("--------------------------------------------\n");
- chksum = checksum_16(ip_hdr_16,sizeof(ip_hdr_16));
- printf("checksum_16 = 0x%04x \n",chksum);
- ip_hdr_16[5] = chksum;
- chksum = checksum_16(ip_hdr_16,20);
- if(chksum)
- printf("Checksum 16 is incorrect! \n");
- else
- printf("Checksum 16 is correct! \n");
- printf("--------------------------------------------\n");
- }