Sword 校验和计算

// IP首部校验和的计算

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

unsigned short checksum(const void *, unsigned int);

#define CHECK_SIZE 24

/*
知识补充:
    为了计算一份数据报的IP检验和,首先把检验和字段置为0。然后,对首部中每个16 bit进行二进制反码求和(整个首部看成是由一串16 bit的字组成),
    结果存在检验和字段中。当收到一份IP数据报后,同样对首部中每个16 bit进行二进制反码的求和。由于接收方在计算过程中包含了发送方存在首部中的检验和,
    因此,如果首部在传输过程中没有发生任何差错,那么接收方计算的结果应该为全1。如果结果不是全1(即检验和错误),那么IP就丢弃收到的数据报。
    但是不生成差错报文,由上层去发现丢失的数据报并进行重传。
*/

union DataIp
{
    char data[CHECK_SIZE];
    unsigned short s[CHECK_SIZE/2];
};

void test()
{
    unsigned short ck = 0;
    union DataIp ip;

    strcpy(ip.data, "123456789abcdef");
    /*
    设计说明:
        假定s[3]为校验位
    */
    ip.s[3] = 0;    // 首先把检验和字段置为0

    // 发送方
    printf("send data is %s .
", ip.data);
    // 校验和计算
    ip.s[3] = checksum(ip.data, CHECK_SIZE);

    // 接收方进行校验和计算
    ck = checksum(ip.data, CHECK_SIZE);

    printf("last check sum is %hu .
", ~ck);

}

unsigned short checksum(const void *data, unsigned int size)
{
    const unsigned char space = sizeof(unsigned short) * 8;         // 单位校验长度(单位bit)
    unsigned short buffer;                                          // 缓冲区
    const unsigned short *p = (const unsigned short *)data;         // 偏移指针
    unsigned int total = 0;

    // 1.参数校验
    if (NULL == data || 0 == size)
    {
        return total;
    }

    // 2,逐位进行运算
    while (size > 1)
    {
        buffer = *p++;
        /*
        设计说明:
            为什么不是 total += ~buffer;
            因为 buffer 的类型是 unsigned short ,当进行+=运算时,编译器会将 buffer 转成unsigned int类型,
            此时 ~buffer操作会导致高位全是1,得出的total结果错误
        */
        total += (unsigned int)(~buffer)&0xffff;
        size -= sizeof(unsigned short);
    }

    // 3.剩余位填充
    if (size)
    {
        buffer = 0;
        memcpy(&buffer, p, size);
        total += (unsigned int)(~buffer)&0xffff;
    }

    // 4.进位处理
    /*
    知识补充:
        校验位是16bit,但是total却是32bit,需要将产生的进位加到低位
       
    */
    while (total >> space)
    {
        //循环操作,直到没有进位为止
        total = (total >> space) + (total & 0xffff);
    }

    return (unsigned short)total;
}


int main(int argc, char *argv[])
{
    test();
    getchar();
    return 0;
}
原文地址:https://www.cnblogs.com/zhanggaofeng/p/12878523.html