You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TCP/ICMP头部长度非2字节倍数时的校验和计算问题

TCP/ICMP校验和单字节处理及代码修复

问题1:单字节剩余时的校验和计算规则

  • TCP、ICMP的校验和计算遵循大端字节序规则,当数据长度为奇数(剩余1字节)时,将该字节作为16位数值的高字节,低字节补0,组成完整的16位字后参与求和计算。
  • 示例:剩余字节为0x63时,转换为0x6300这个16位值,再纳入校验和累加流程。

问题2:代码修复与单字节处理实现

你的代码仅处理了偶数长度的分段(size/2次循环),完全遗漏了最后一个奇数字节。以下是修复后的代码,同时修正原代码中初始化和进位处理的问题:

#include <stdint.h>
#include <arpa/inet.h>
#include <stdio.h>

int calculate_checksum(void *vdata, size_t size)
{
    uint16_t *ptr = vdata;
    uint32_t sum = 0; // 用32位变量存储累加和,简化溢出处理

    printf("size = %zu\n", size);

    // 处理所有完整的16位字
    while (size >= 2)
    {
        sum += ntohs(*ptr);
        printf("0x%x 0x%x\n", ntohs(*ptr), (uint16_t)(sum & 0xFFFF));
        ptr++;
        size -= 2;
    }

    // 处理剩余的单个字节
    if (size == 1)
    {
        uint16_t last_word = *(uint8_t *)ptr << 8; // 单字节作为高字节,低字节补0
        sum += last_word;
        printf("0x%x 0x%x\n", last_word, (uint16_t)(sum & 0xFFFF));
    }

    // 统一处理累加过程中的进位:将高16位加到低16位,直到无进位
    while (sum >> 16)
    {
        sum = (sum & 0xFFFF) + (sum >> 16);
    }

    // 取反得到校验和,转换为网络字节序返回
    uint16_t checksum = ~sum & 0xFFFF;
    printf("checksum = 0x%x\n", checksum);
    return htons(checksum);
}

关键修复点说明

  1. 单字节处理逻辑:当size剩余1时,将最后一个字节左移8位(大端序补0),组成16位字加入累加和。
  2. 累加和变量优化:改用uint32_t存储累加和,避免频繁判断溢出,最后统一处理进位更简洁。
  3. 进位处理标准化:循环将高16位的进位合并到低16位,符合TCP/IP校验和的标准计算流程。
  4. 初始化修正:原代码sum = -0xffff错误,标准校验和初始化应为0,累加完成后取反得到结果。

内容的提问来源于stack exchange,提问作者user786

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 04:45:14