一、8位校验和的实现

1.发送端计算8位校验和的步骤:

  (1)把校验和字段设置为0。

  (2)把需要校验的数据看成以8位为单位的数字组成,依次进行求和,得到的和二进制求反码,再加上1,最终得到校验和。

  (3)把得到的结果存入校验和字段中。

2.接收端校验校验和步骤:

  (1)把需要校验的内容(包括校验和字段)看成以8位为单位的数字,依次进行二进制反码求和,如果结果是0表示正确,否则表示错误。

3.实现代码:

 

1 static unsigned char sg_ucSeq = 0;
 2 typedef struct
 3 {
 4     unsigned long hid;
 5     unsigned long cid;
 6     unsigned char type;
 7     unsigned char len;    
 8     unsigned char checksum;
 9     unsigned char seq;
10 
11     unsigned char userData[MAX_USER_DATA_SIZE];
12 }DATA_T;
13 
14 #define MAX_USER_DATA_SIZE       40
15 #define DATA_HEADER_LEN (sizeof(DATA_T) - MAX_USER_DATA_SIZE)
16 
17 unsigned char MakeCheckSum8(DATA_T *pData)
18 {
19     unsigned char ucCheckSum = 0;
20     unsigned char ucNum;
21     unsigned char *pucDat = (unsigned char *)pData;
22 
23     // 以1byte为单位依次相加
24     for(ucNum=0;ucNum<pData->len;ucNum++){
25         ucCheckSum += pucDat[ucNum];
26     }
27 
28     // 二进制求反码,并加1,得到校验和
29     ucCheckSum = ~ucCheckSum;
30     ucCheckSum++;
31     
32     return ucCheckSum;
33 }
34 
35 unsigned char CheckData8(DATA_T *pData)
36 {
37     unsigned char ucCheckSum = 0;
38     unsigned char ucNum;
39     unsigned char *pucDat = (unsigned char *)pData;
40 
41     for(ucNum=0;ucNum<pData->len;ucNum++){
42         ucCheckSum += pucDat[ucNum];
43     }
44     
45     return ucCheckSum;
46 }
47 void create_common_msg(DATA_T *pfdata, unsigned char type, unsigned char *pdata, int len)
48 {
49     memset(pdata, 0, sizeof(DATA_T));
50 
51     pfdata->cid = 0x12345678;
52     pfdata->type = type;
53     pfdata->len = DATA_HEADER_LEN + len;
54     pfdata->checksum = 0;
55     pfdata->seq = sg_ucSeq++;
56 
57     if (len > 0)
58     {
59         memcpy(pfdata->userData, pdata, len);
60     }
61 
62     pfdata->checksum     = MakeCheckSum8(pdata);
63 
64     return;
65 }

 

二、16位校验和的实现

1.计算校验和的步骤:

 (1)把校验和字段设置为0。

 (2)把需要校验的数据看成以16位为单位的数字组成,依次进行二进制反码求和。

 (3)把得到的结果存入校验和字段中。

 另外UDP、TCP数据报的长度可以为奇数字节,因为计算时是16位为单位,所以此时计算校验和时需要在最后增加一个填充字节0(只是计算校验和用,不发送出去)。

2.接收端校验校验和步骤:

 (1)把需要校验的内容(包括校验和字段)看成以16位为单位的数字,依次进行二进制反码求和,如果结果是0表示正确,否则表示错误。

3.二进制反码求和步骤:

 (1)二进制反码求和,就是先把这两个数取反,然后求和,如果最高位有进位,则向低位进1。

 (2)另外,先取反后相加与先相加后取反,得到的结果是一样的。因此实现代码都是先相加,最后再取反。

4.实现代码:

1 static inline unsigned short  check_sum(const unsigned short *buf, int size)
 2 {
 3     unsigned long chksum = 0;
 4     
 5     //16位为单位数字相加
 6     while(size>1)
 7     {
 8         chksum += *buf++;                    // 对传入的数据以unsigned short方式解析
 9         size -= sizeof(unsigned short );
10     }
11 
12     //长度奇数情况
13     if(size)
14     {
15         chksum += *((unsigned char *)buf);
16     }
17     
18     //高位有进位,进位到低位,下面两行代码保证了高16位为0。
19     while (chksum >> 16) 
20     {  
21         chksum = (chksum >> 16) + (chksum & 0xffff);  
22     } 
23     
24     //最后取反
25     return (unsigned short )(~chksum);
26 }

三、32位校验和的实现

1.发送端计算32位校验和的步骤:

  (1)把校验和字段设置为0。

  (2)把需要校验的数据看成以32位为单位的数字组成,依次进行求和,得到的和二进制求反码,再加上1,最终得到校验和。

  (3)把得到的结果存入校验和字段中。

2.接收端校验校验和步骤:

  (1)把需要校验的内容(包括校验和字段)看成以32位为单位的数字,依次进行二进制反码求和,如果结果是0表示正确,否则表示错误。

3.实现代码:

1 unsigned int make_checksum_32(unsigned char *pdata, int dataLen)
 2 {
 3     int len;
 4     unsigned int chk = 0;
 5     
 6     // 按照小端的方式计算4个字节的checksum
 7     len = dataLen;
 8     while (len >= 4)
 9     {
10         chk +=   (unsigned int)pdata[0];                //     ----          ----         ----       pdata[0]
11         chk +=   ((unsigned int)pdata[1] << 8);         //     ----          ----        pdata[1]     ----
12         chk +=   ((unsigned int)pdata[2] << 16);        //     ----         pdata[2]      ----        ----
13         chk +=   ((unsigned int)pdata[3] << 24);        //     pdata[3]      ----         ----        ----
14 
15         pdata += 4;
16         len -= 4;
17     }
18     
19     if (len > 0)
20     {
21         if (len == 1)
22         {
23             chk +=   (unsigned int)pdata[0];
24         }
25         else if (len == 2)
26         {
27             chk +=   (unsigned int)pdata[0];
28             chk +=   ((unsigned int)pdata[1] << 8);
29         }
30         else 
31         {
32             chk +=   (unsigned int)pdata[0];
33             chk +=   ((unsigned int)pdata[1] << 8);
34             chk +=   ((unsigned int)pdata[2] << 16);
35         }
36     }
37 
38     chk = ~chk;
39     chk++;
40 
41     return chk;
42 }