相信TCP校驗和函數執行以下操作:瞭解TCP校驗和函數
- 的僞首和TCP片段報頭和數據分裂成2個字節的塊。
- 如果長度不是2個字節,則在最後一個塊的末尾添加一個0字節的填充字以使其爲2個字節。
- 取總和的補碼得到TCP校驗和。
聽起來很簡單。因此,我寫我自己的通用checksum
功能:
#include <inttypes.h>
#include <arpa/inet.h>
uint16_t checksum(uint16_t * data, int size) {
uint16_t sum = 0;
int i = 0, length = size/2;
while (i < length) sum += data[i++];
if (size % 2) sum += data[i] & 0xFF00;
return htons(~sum);
}
但是其他人都寫checksum
功能,這似乎更復雜。例如:
uint16_t checksum(uint16_t * addr, int len) {
int nleft = len;
int sum = 0;
uint16_t * w = addr;
uint16_t answer = 0;
while (nleft > 1) {
sum += *w++;
nleft -= sizeof(uint16_t);
}
if (nleft == 1) {
*(uint8_t *) (&answer) = *(uint8_t *) w;
sum += answer;
}
sum = (sum >> 16) + (sum & 0xFFFF);
sum += (sum >> 16);
answer = ~sum;
return (answer);
}
我有一個關於這個代碼的一些問題:
- 這句話是什麼
*(uint8_t *) (&answer) = *(uint8_t *) w;
實際上呢? 爲什麼我們採取的總和:
sum = (sum >> 16) + (sum & 0xFFFF); sum += (sum >> 16);
有沒有計算TCP校驗和變更的方式嗎?
我真的不明白我們爲什麼做sum = (sum >> 16) + (sum & 0xFFFF)
。考慮sum
是0xABCD
:
0xABCD >> 16 == 0x0000
0xABCD & 0xFFFF == 0xABCD
0x0000 + 0xABCD == 0xABCD
這似乎是一個多餘的一步。下一條語句sum += (sum >> 16)
也是如此。
看起來像'sum =(sum >> 16)+(sum&0xFFFF)'是爲了將所有數據包裝成16位整數,因此在第二個例子中,sum是聲明爲'int sum = 0;' – deimus
對於問題1,按照RPC 793填充8位零的最後一個字。 – Jiminion
請注意,校驗和是以補碼形式完成的。這不同於簡單地用'sum + = ...'來包裝溢出的uint16_t。 – nos