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

基于字节数组计算TCP校验和遇错求助(附C#代码)

TCP校验和计算错误排查与修正建议

核心错误点排查

1. 伪头部长度字段问题

TCP伪头部的长度字段是TCP段总长度(TCP头+负载字节数),需按网络字节序(大端)存储,且为16位值。常见错误:

  • 误将IPv4总长度当作该值,或计算时遗漏TCP头长度(需从TCP头的Data Offset字段获取,单位为4字节)
  • 长度值未转换为大端字节序就加入伪头部

2. 一的补码计算逻辑错误

TCP校验和标准计算流程:

  1. 拼接伪头部、校验和字段设为0的TCP头、负载为连续字节数组
  2. 按16位为一组累加,若总字节数为奇数,末尾补0字节
  3. 将累加产生的进位(超过16位的部分)加到低16位上
  4. 对最终16位值取反,得到的一的补码即为校验和

常见错误:

  • 累加时未处理跨16位的进位,直接截断低16位
  • 取反操作未考虑C#中int的符号位,需先转成ushort再取反

修正后的C#代码示例

假设输入为IPv4头字节数组ipHeader、TCP头字节数组tcpHeader、负载字节数组payload,以下是正确计算逻辑:

public ushort CalculateTcpChecksum(byte[] ipHeader, byte[] tcpHeader, byte[] payload)
{
    // 构造伪头部
    List<byte> pseudoHeader = new List<byte>();
    // 源IP(IPv4头第12-15字节)
    pseudoHeader.AddRange(ipHeader.Skip(12).Take(4));
    // 目的IP(IPv4头第16-19字节)
    pseudoHeader.AddRange(ipHeader.Skip(16).Take(4));
    // 保留字段(固定为0)
    pseudoHeader.Add(0);
    // 协议号(TCP为6)
    pseudoHeader.Add(6);
    // TCP总长度(TCP头+负载,转网络字节序)
    ushort tcpTotalLength = (ushort)(tcpHeader.Length + payload.Length);
    pseudoHeader.AddRange(BitConverter.GetBytes(IPAddress.HostToNetworkOrder((short)tcpTotalLength)));

    // 拼接校验计算用的完整数据
    List<byte> checksumData = new List<byte>(pseudoHeader);
    // 复制TCP头并将校验和字段(第16-17字节)清零
    byte[] tcpHeaderZeroed = (byte[])tcpHeader.Clone();
    tcpHeaderZeroed[16] = 0;
    tcpHeaderZeroed[17] = 0;
    checksumData.AddRange(tcpHeaderZeroed);
    checksumData.AddRange(payload);

    // 按16位累加并处理进位
    uint sum = 0;
    int i = 0;
    while (i < checksumData.Count)
    {
        // 按网络字节序解析16位值
        ushort value = (ushort)((checksumData[i] << 8) | checksumData[i + 1]);
        sum += value;
        // 处理进位:将高16位叠加到低16位
        if ((sum & 0xFFFF0000) != 0)
        {
            sum = (sum & 0xFFFF) + (sum >> 16);
        }
        i += 2;
    }
    // 处理奇数长度的末尾字节
    if (checksumData.Count % 2 != 0)
    {
        sum += checksumData[checksumData.Count - 1];
        if ((sum & 0xFFFF0000) != 0)
        {
            sum = (sum & 0xFFFF) + (sum >> 16);
        }
    }

    // 取反得到最终校验和(转ushort避免符号位干扰)
    return (ushort)~sum;
}

关键验证点

  • 伪头部TCP总长度:比如TCP头20字节+负载100字节,总长度120,转大端后应为0x0078
  • 累加字节序:网络字节序16位值高字节在前,需将第一个字节左移8位加第二个字节
  • 进位处理:若累加后sum为0x12345,需转换为0x2345 + 0x1 = 0x2346
  • 取反操作:必须针对16位无符号数,避免C# int类型符号位的影响

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 02:05:14