了解TCP校验和函数 [英] Understanding the TCP checksum function
问题描述
我相信TCP校验和函数执行以下操作:
I believe that the TCP checksum function does the following:
- 将伪标头和TCP段标头和数据分成2字节
- 如果长度不是2个字节,请将最后一个块的末尾添加一个0字节的填充字节,以使其成为2个字节。
听起来很简单。因此,我写了我自己的泛型校验和
函数:
Sounds simple enough. Hence I wrote my own generic checksum
function:
#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);
}
但是其他人写了校验和
似乎更复杂的函数。例如:
However other people have written checksum
functions which seem to be more complicated. For example:
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);
}
我对此代码有几个问题:
I have a few questions regarding this code:
- 语句
*(uint8_t *)(& answer)= *(uint8_t *)w;
实际上是什么? -
为什么我们将总和视为:
- What does the statement
*(uint8_t *) (&answer) = *(uint8_t *) w;
actually do? Why do we take the sum as:
sum = (sum >> 16) + (sum & 0xFFFF);
sum += (sum >> 16);
计算TCP校验和的方法是否改变?
Did the way to calculate the TCP checksum change?
我真的不明白为什么我们做 sum =(sum>> 16)+(sum& 0xFFFF )
。考虑 sum
是 0xABCD
:
I really don't see why we do sum = (sum >> 16) + (sum & 0xFFFF)
. Consider sum
is 0xABCD
:
0xABCD >> 16 == 0x0000
0xABCD & 0xFFFF == 0xABCD
0x0000 + 0xABCD == 0xABCD
一个冗余步骤。对于下一语句 sum + =(sum>> 16)
也是如此。
It seems like a redundant step. Same goes for the next statement sum += (sum >> 16)
.
推荐答案
校验和函数仅适用于大端处理器。
The checksum function appears to be for big-endian processors only.
第一个while循环针对速度进行了优化。
The first while loop is optimized for speed.
& answer
特技将最后一个字节(如果有奇数个字节)类似于你的代码对 data [i]& data的操作,字节
。它的工作方式是这 answer
0xff00
The &answer
trick loads the last byte (if there were an odd number of bytes) into the high byte of answer
, leaving the low byte zero, similar to what your code does with data[i] & 0xff00
. The way it works is this
1) take the address of answer (&answer)
2) convert that to a byte pointer (uint8_t *)
2a) on a big endian processor the first byte of a 16-bit quantity is the high byte
3) overwrite the high byte with the last byte of the data
校验和应该计算与载入的加载。这里假设这个代码正在运行在 int
是32位的机器上。因此,(sum& 0xffff)
是16位校验和,(sum>> 16)
是需要加回的进位位(如果有的话)。因此,行
The checksum is supposed to be computed with the carries added back in. It's assumed here that this code is running on a machine where an int
is 32-bits. Therefore, (sum & 0xffff)
is the 16-bit checksum, and (sum >> 16)
are the carry bits (if any) that need to be added back in. Hence, the line
sum = (sum >> 16) + (sum & 0xffff);
调整总和以包括进位。然而,该行代码本身可以产生另一进位位。因此,下一行 sum + =(sum>> 16)
将携带(如果有)返回到校验和。
adjusts the sum to include the carries. However, that line of code could itself generate another carry bit. So the next line sum += (sum >> 16)
adds that carry (if any) back into the checksum.
最后,采取答案的补充。注意,不使用 htons
,因为整个函数隐含地假定它在大端处理器上运行。
Finally, take the ones-complement of the answer. Note that htons
is not used since the whole function implicitly assumes that it is running on a big endian processor.
这篇关于了解TCP校验和函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!