【发布时间】:2022-01-24 08:01:05
【问题描述】:
因此,到目前为止,此函数只是在将 0 设置为校验和后将 struct iphdr 对象中的每个单词相加并进行补码。但是有一些问题,因为我收到的 ip 数据包校验和字段是完全不同的。我计算的结果是负值
所以这是我的校验和函数,下面是简单的
uint16_t ip_checksum(void* vdata,size_t length) {
// Cast the data pointer to one that can be indexed.
char* data=(char*)vdata;
uint32_t acc=0;
// Handle complete 16-bit blocks.
for (size_t i=0;i+1<length;i+=2) {
uint16_t word;
memcpy(&word,data+i,2);
acc+=ntohs(word);
/*if (acc>0xffff) {
acc-=0xffff;
}*/
}
return (~acc);
}
所以这个循环
for (size_t i=0;i+1<length;i+=2) {
uint16_t word;
memcpy(&word,data+i,2);
acc+=ntohs(word);
/*if (acc>0xffff) {
acc-=0xffff;
}*/
}
只是对接收到的对象指针的每个 16 位字进行操作,并进行加法并将其存储在 acc 变量中,
然后我用~ 来补充它
return (~acc);
所以基本上,如果我是正确的,我在互联网上确切地告诉计算它。但是当我这样做时
printf("checksum = %d\n",ntohs(iph->check));
iph->check=0;
int16_t i=ip_checksum(iph,sizeof(iph));
printf("------------------------------------------>%d\n",(i));
它在上面的两个 printf 中打印完全不同的校验和值。 所以我想知道我做错了什么
【问题讨论】:
-
如果你的数据大小不是2的倍数,那么
memcpy(&word,data+i,2)就是麻烦的来源。 -
如果它是 2 的倍数(总是),那么你最好用
i<length替换i+1<length(我的意思是,也许它可以完成工作,也许它错过了最后一个2 个字符;如果我是你,那我宁愿不用问自己这个问题)。 -
@bbbbbbbbb 我在校验和函数中尝试了这个
printf("))))))))))))))))))))))%zu\n",length);,它的打印是 8 它是 2 的倍数你是什么意思。 -
最后,
memcpy(&word,data+i,2)始终按照 Little Endian 顺序完成,而uint16_t word则受制于您平台的字节顺序。这意味着你会在不同的平台上得到不同的结果,这使得你的程序的行为没有很好的定义。 -
编辑问题以提供minimal reproducible example,包括重现问题的数据、观察到的输出和所需的输出。解释为什么您注释掉了
0xffff部分,而这是校验和的必要部分。说明长度是字节数还是字数。
标签: c networking tcp ip checksum