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