计算以太网包首部中使用的校验和
算法: first summing all numbers(every 16-bit, might with padding)
and adding the carry (or carries) to the result,
then compute ones' complement
:
– 发送端或接收端计算发送端的校验和时, 需要首先把校验和字段设置为 0
– 然后累积每个 16-bit
– 然后将最终结果"折叠"
成 16 bits
– 然后 ones' complement
(算法: 所有按位取反)
– 最后只要低 16 bits, 最后结果是网络字节顺序
/**
* 计算以太网包首部中使用的校验和
* @param data data to compute, in network byte order
* @param bytes data size in bytes
* @return in network byte order
*/
uint16_t ComputeChecksum(uint16_t const* const data, size_t const bytes)
{
// initialize sum to zero
unsigned long sum = 0;
// n to keep current left bytes
size_t n;
// data index for each 16-bit
long dataIndex;
// accumulate sum
for (n = bytes, dataIndex = -1; n > 1; n -= 2) {
sum += data[++dataIndex];
}
/*
* if any bytes left, pad the bytes with 0x00 and add
* 最后一个 16-bit, 网络字节序:
* 最后一个字节(位于最后一个 16-bit高位): MSB, then 0x00,
* 而 MSB 在低地址, 因此计算使用最后一个 16-bit 是 0x00 then 最后一个字节:
* - 即最后一个字节,
* - => ((data[++dataIndex] >> 8) & 0xff) ... but data[...] bad
* - => ((data[++dataIndex]) & htons(0xff00) ... but data[...] bad
* - => uint8_t const msb = (reinterpret_cast<uint8_t const* const>(data))[
* long(bytes) - 1];
*/
if (n > 0) {
uint8_t const msb = (reinterpret_cast<uint8_t const* const>(data))[
long(bytes) - 1];
sum += msb;
}
// fold sum to 16 bits: add carrier to result
while (sum >> 16) {
sum = (sum >> 16) + (sum & 0xffff);
}
/*
* ones' complement:
* The ones' complement of a binary number is defined as the value
* obtained by inverting all the bits in the binary representation of the
* number (swapping 0s for 1s and vice versa)
*/
return uint16_t(~sum);
}