TCP校验和(Checksum)的原理和实现

TCP校验和(Checksum)的原理和实现_造梦先森Kai的专栏-CSDN博客_tcp校验和

概述

TCP校验和(Checksum)是一个端到端的校验和,由发送端计算,然后由接收端验证。其目的是为了发现TCP首部和数据在发送端到接收端之间发生的任何改动。如果接收方检测到校验和有差错,则TCP段会被直接丢弃。

TCP校验和覆盖TCP首部和TCP数据,而IP首部中的校验和只覆盖IP的首部,不覆盖IP数据报中的任何数据。TCP校验和、IP校验和的计算方法是基本一致的,除了计算的范围不同。

TCP的校验和是必需的,而UDP的校验和是可选的。TCP和UDP计算校验和时,都要加上一个12字节的伪首部。

伪首部

首先解释下伪首部的概念,伪首部的数据都是从IP数据报头获取的。其目的是让TCP检查数据是否已经正确到达目的地,只是单纯为了做校验用的。

struct 
{
unsigned long saddr;  //源地址
unsigned long daddr; //目的地址
char mbz; //强制置空
char ptcl; //协议类型
unsigned short tcpl; //TCP长度
}psd_header;

伪首部共有12字节(前96Bits),包含如下信息:源IP地址、目的IP地址、保留字节(置0)、传输层协议号(TCP是6)、TCP报文长度(报头+数据)。

伪首部是为了增加TCP校验和的检错能力:如检查TCP报文是否收错了(目的IP地址)、传输层协议是否选对了(传输层协议号)等。
 

校验和计算

RFC 793的TCP校验和定义:
The checksum field is the 16 bit one’s complement of the one’s complement sum of all 16-bit words in the header and text. If a segment contains an odd number of header and text octets to be checksummed, the last octet is padded on the right with zeros to form a 16-bit word for checksum purposes. The pad is not transmitted as part of the segment. While computing the checksum, the checksum field itself is replaced with zeros.

上述的定义说得很明确:
首先,把伪首部、TCP报头、TCP数据分为16位的字,如果总长度为奇数个字节,则在最后增添一个位都为0的字节。把TCP报头中的校验和字段置为0(否则就陷入鸡生蛋还是蛋生鸡的问题)。
其次,用反码相加法累加所有的16位字(进位也要累加)。
最后,对计算结果取反,作为TCP的校验和。

举个例子来解释该校验方法:


1、首先将检验和置零;
2、然后将TCP伪首部部分,TCP首部部分,数据部分都划分成16位的一个个16进制数
3、将这些数逐个相加,记得溢出的部分加到最低位上,这是循环加法:
0xc0a8+ 0x0166+……+0x0402=0x9b49
4、最后将得到的结果取反,则可以得到检验和位0x64b6

校验和反码求和 的实现

发送方:原码相加 ,并将高位叠加到低位,取反 ,得到反码求和结果,放入校验和
接收方:将所有原码 相加,高位叠加, 如全为1,则正确

下面为C实现较为原始的checksum算法,代码中对于算法做了比较详细的注释:

unsigned short 
checksum(unsigned short * addr, int count)

{
long sum = 0;
/*
计算所有数据的16bit对之和
*/
    while( count > 1  )  {
        /*  This is the inner loop */
        sum += *(unsigned short*)addr++;

        count -= 2
    }   

/* 如果数据长度为奇数,在该字节之后补一个字节(0),
   然后将其转换为16bit整数,加到上面计算的校验和
  中。
 */
    if( count > 0 ) { 
        char left_over[2] = {0};
        left_over[0] = *addr;
        sum += * (unsigned short*) left_over;
    }   

/*  将32bit数据压缩成16bit数据,即将进位加大校验和
  的低字节上,直到没有进位为止。
 */
    while (sum>>16)
        sum = (sum & 0xffff) + (sum >> 16);
  
   /*返回校验和的反码*/
   return ~sum;
}

  • 5
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个计算TCP校验和的C语言代码: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <netinet/in.h> unsigned short checksum(unsigned short *buf, int nwords) { unsigned long sum; for(sum=0; nwords>0; nwords--) sum += *buf++; sum = (sum >> 16) + (sum &0xffff); sum += (sum >> 16); return (unsigned short)(~sum); } int main() { char data[] = "Hello, world!"; int datalen = strlen(data); char src_ip[] = "192.168.0.1"; char dst_ip[] = "192.168.0.2"; unsigned short src_port = 1234; unsigned short dst_port = 5678; char packet[4096]; memset(packet, 0, sizeof(packet)); struct iphdr *iph = (struct iphdr *)packet; struct tcphdr *tcph = (struct tcphdr *)(packet + sizeof(struct iphdr)); iph->ihl = 5; iph->version = 4; iph->tos = 0; iph->tot_len = sizeof(struct iphdr) + sizeof(struct tcphdr) + datalen; iph->id = htons(54321); iph->frag_off = 0; iph->ttl = 255; iph->protocol = IPPROTO_TCP; iph->check = 0; iph->saddr = inet_addr(src_ip); iph->daddr = inet_addr(dst_ip); tcph->source = htons(src_port); tcph->dest = htons(dst_port); tcph->seq = htonl(1); tcph->ack_seq = 0; tcph->doff = 5; tcph->fin = 0; tcph->syn = 1; tcph->rst = 0; tcph->psh = 0; tcph->ack = 0; tcph->urg = 0; tcph->window = htons(5840); tcph->check = 0; tcph->urg_ptr = 0; memcpy(packet + sizeof(struct iphdr) + sizeof(struct tcphdr), data, datalen); tcph->check = checksum((unsigned short *)(packet + sizeof(struct iphdr)), sizeof(struct tcphdr) + datalen); printf("TCP checksum: 0x%x\n", tcph->check); return 0; } ``` 这个代码可以计算TCP报文的校验和,其中包括IP头和TCP头,以及TCP数据。你可以将需要发送的数据放在`data`数组中,将源IP地址和目的IP地址放在`src_ip`和`dst_ip`字符串中,将源端口和目的端口放在`src_port`和`dst_port`变量中。最终计算出的校验和会被存放在`tcph->check`变量中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值