【问题标题】:RFC 1071 checksum for char array字符数组的 RFC 1071 校验和
【发布时间】:2019-02-20 22:33:10
【问题描述】:

我很难理解来自RFC 1071 的以下校验和算法:

The following "C" code algorithm computes the checksum with an inner
loop that sums 16-bits at a time in a 32-bit accumulator.

in 6
{
    /* Compute Internet Checksum for "count" bytes
    *         beginning at location "addr".
    */
    register long sum = 0;

    while( count > 1 )  {
        /*  This is the inner loop */
        sum += * (unsigned short) addr++;
        count -= 2;
    }

    /*  Add left-over byte, if any */
    if( count > 0 )
        sum += * (unsigned char *) addr;

    /*  Fold 32-bit sum to 16 bits */
    while (sum>>16)
        sum = (sum & 0xffff) + (sum >> 16);
    
    checksum = ~sum;
}

我的目标是获取一个 char 数组并计算其校验和,但我不确定未定义的变量是什么。 addrchecksum 的数据类型是什么和/或,如何将 char 数组转换为可用于校验和过程的格式?我知道 count 是存储在 addr 中的字节数。

编辑:到目前为止,我正在考虑将 char 数组转换为整数,然后获取字节数:

int char_int = sscanf(char_array, "%d", &i);
int addr = char_int;
int count = sizeof(char_int);

【问题讨论】:

  • 我可以告诉你,你绝对不想想使用sscanf(char_array, "%d", &i);它将像"1234"这样的写出数字转换为二进制,而此示例代码旨在将N个原始字节序列视为已经是(N / 2)个16位二进制数序列。我还可以告诉您,显示的代码非常陈旧,并且在现代 C 中所做的事情被认为是不正确的,因此您可能不应该将其用作参考。很遗憾,我没有更好的参考资料供您参考。

标签: c checksum


【解决方案1】:

由于内部循环以 16 位增量处理数据,addr 必须是指向 16 位值的指针,即uint16_t * addr

checksum 是您希望存储最终结果的任何数据类型。如果您要计算 16 位校验和,它也应该是 uint16_t

请注意,sum 可能应该是 unsigned long,而不是 long。它在实践中有效,因为网络数据包通常不够大,以至于校验和会溢出long(数据包必须至少为 32K 字节)。但是,如果您正在编写通用代码,则应该进行防御性编码。

您可以在以下位置找到使用适当的可移植数据类型的实现:

http://www.microhowto.info/howto/calculate_an_internet_protocol_checksum_in_c.html

uint16_t ip_checksum(void* vdata,size_t length) {
    // Cast the data pointer to one that can be indexed.
    char* data=(char*)vdata;

    // Initialise the accumulator.
    uint32_t acc=0xffff;

    // 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;
        }
    }

    // Handle any partial block at the end of the data.
    if (length&1) {
        uint16_t word=0;
        memcpy(&word,data+length-1,1);
        acc+=ntohs(word);
        if (acc>0xffff) {
            acc-=0xffff;
        }
    }

    // Return the checksum in network byte order.
    return htons(~acc);
}

【讨论】:

  • 我也注意到该解决方案在线,但没有像我的情况那样使用它,我正在尝试计算 int,而不是 unsigned int 校验和并且无法导入uint16_6 的库。如果我应该早点指定,我深表歉意。
  • @Paradox 它是uint16_t,在&lt;stdint.h&gt; 中可用。
  • @Paradox 如果没有stdint.h,则将uint16_t 的所有用法替换为unsigned short,还包括limits.h 并放入#if USHRT_MAX != 65535 #error "Code below assumes unsigned short is 16 bits" #endif就在包含之后。
猜你喜欢
  • 1970-01-01
  • 2011-11-05
  • 1970-01-01
  • 2021-11-29
  • 2012-11-20
  • 2012-04-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多