5、checksum(校驗和)的實現


一、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 }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM