前一段时间,我需要一个函数来执行校验和,以在通过Internet交换数据报时测试数据的完整性。那些日子,我发现了此功能,只是复制/粘贴并使用它。
Checksum (void* buf, int bufsize) {
register int sum = 0;
word answer = 0;
register word *w = (word*) buf;
register int nleft = bufsize;
while (nleft > 1) {
sum += *w++;
nleft -= 2;
}
if (nleft == 1) {
*(byte*)(&answer) = *(byte*)w;
sum += answer;
}
sum = (sum>>16) + (sum&0xFFFF);
sum += (sum>>16);
answer = ~sum;
return answer;
}
今天,我正在开发另一个需要校验和以确保数据完整性的程序,但是这次我想看看它是如何工作的,并且对此表示怀疑。
该算法将数据缓冲区中的所有字相加,然后将进位(高位字,如果有的话)加到总和上,最后取和(一个补码),因此它是校验和值。
我的具体问题是:
缓冲区中的单词应该是小端还是大端?我的直觉告诉我,字字节应使用BIG ENDIAN(按惯例),因此任何计算机的校验和都是相同的,但是此算法只是对值进行求和(在x86平台上为little endian),如果另一端是?一个大的字节序平台?如果我将小端和大端直接反转的字节值相加,仍然可以工作吗?
如果缓冲区大小为奇数,则将最后一个字节直接添加到总和,但将其作为值或作为单词的LOW ORDER字节添加(考虑到下一个字节为0-HIGH)小尾数的ORDER字节)?
它是用于具有校验和支持的简单通信协议,但必须确保它可以独立于其体系结构在任何平台上工作。
答案 0 :(得分:0)
- 缓冲区中的单词是尾数大还是小?
用于网络连接(使用任何协议通过网络发送或接收的任何数据包的“有效负载”); 缓冲区始终包含八位字节(字节),并且八位字节的到达顺序始终与发送顺序相同(没有“字节顺序”问题)。
在软件使用网络通过网络发送数据之前,它会将某些内容(例如高级语言的结构)转换为八位字节的缓冲区。这称为“序列化”,对于避免各种可移植性灾难(不仅是“内在性”,还包括编译器/实现特定的结构填充,浮点格式差异,字符集差异等)是必需的。
软件从网络接收数据后,会将八位位组的缓冲区转换为某种内容(例如高级语言的结构)。这称为“反序列化”。它涉及三个目的:
这一切(序列化和反序列化)都不是网络本身的一部分-它们是“在网络之前”和“在网络之后”,而不是“在网络中间”。
请注意(根据您的问题),您已经假定缓冲区是高级结构,并且未能序列化/反序列化;因此您的代码(包括您的校验和)被破坏了并且将失败(并且可能不仅仅是因为“ endianess”)。
- 如果缓冲区大小为奇数,则将最后一个字节直接添加到总和中,但将其作为值或作为单词的LOW ORDER字节添加(考虑到下一个字节为0-IN中的HIGH ORDER字节)小尾数)?
是的
请注意,校验和计算的主要部分(错误地认为“八位字节的缓冲区”是单词)将由于“字节序”而中断(如果发送方和接收方具有不同的字节序,则校验和将校验“将”(请参见注释) )对于大于1个八位位组的所有邮件均失败)。避免这种情况的简单方法是使用“字节总和”(而不是“字数总和”)。避免这种情况的更好方法是使用更复杂的校验和(例如TCP使用的CRC-32)。
注意:对于16位校验和,在65536中至少有1次机会仅由于运气就偶然通过了校验和;而且“总和”方法容易遭受各种失败(例如,如果发送方或接收方的消息大小错误,并且结尾不应该有很多零,那么“不正确的零”将不起作用)校验和)。这意味着,当发送者和接收者使用相同的字节序时,校验和将在不通过校验和的情况下通过的概率“比65差1”。这也意味着当发送方和接收方使用不同的字节序并且消息大于1个八位位组时,校验和将在“应该”通过时有“超过1个八位字节”的机会。