相信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