当前位置:文档之家› 计算机网络课设 计算校验和

计算机网络课设 计算校验和

课程设计任务书目录摘要1 课程设计目的 (1)2 课程设计要求 (1)3 相关知识 (5)4 课程设计分析 .................................. 错误!未定义书签。

15 程序代码........................................... 错误!未定义书签。

26 运行结果与分析 (123)7 实验体会 (13)8 参考文献 (133)网络上的数据最终都是通过物理传输线路进行传输的,如果高层没有采用差错控制,那么物理层传输的数据的正确性,在物理层的基础上设计了数据链路,以向网络层提高质量的服务。

目前,进行差错检测和控制的主要方法是发送方在需要发送的数据后面增加一定的冗余信息,这些冗余信息通常是通过对发送的数据进行某种算法计算而得到的。

接收方对接收数据进行同样的计算,然后与数据后面附加的冗余信息进行比较,如果比较结果不同就说明在传输中出现了差错,并要求发送方重新传送该数据,以此达到确保数据准确性的目的。

在普通使用的网络协议(例如IP,ICMP,IGMP,UDP与TCP等)中,通常都设置了校验和字段以保存这些冗余信息。

计算这些校验和的算法称为网络校验和算法,就是将被校验的数据按16位进行累加,然后取反码,如果数据字节长度为奇数,则数据尾部补一个字节的0以凑成偶数。

关于计算校验和算法的详细信息请参考RFC1071。

2.计算校验和(1)交换性与结合性因为校验和主要考虑被校验数据中所包含字节数量的是奇数还是偶数,所以校验和的计算可以以任意顺序进行,甚至可以把数据进行分组后再计算。

例如,用A、B、C、D,……,Y,Z分别表示一系列八位组,用[a,b]这样形式的字节来表示a*256+b 的整数,那么16位校验和就可以通过以下形式给出:[A,B]+’[C,D]+’……+’[Y,Z] [1][A,B]+’[C,D]+’……+’[Z,0] [2]在这里,+’代表1补数加法,即将前面的16位校验和按位取反。

[1]可以以([A,B]+’[C,D]+’……+’[J,0]+’([0,K]+’……+’[Y,Z]) [3]的形式进行计算。

(2)字节顺序的自主性打破被校验数据中的字节顺序仍可以计算出正确的16位校验和。

例如,我们交换字节组中两字节的顺序,得到[B,A]+’[D,C]+’……+’[Z,Y] [4]所得到的得结构与[1]式是相同的(当然结果也是要进行一次反转的)。

为什么会是这样呢?我们发现两种顺序获得的进位是相同的,都是从第15位到第0位进位以及从第7位到第8位进位。

这也就是说,交换字节位置只是改变高低位字节的排列顺序,但并没有改变它们的内在联系。

因此,无论底层的硬件设置中对字节的接收顺序如何,校验和都可以被准确地校验出来。

例如,假设校验和是以主机序(高位字节在前低位字节在后)计算的数据帧,但以网络序(低位字节在前高位字节在后)存放在内存中。

每一个16位的字中的字节在传送过程中都交换了顺序,在计算校验和之后仍会先交换位置再存入内存,这样就与接受到的原本以网络序存储的数据帧中的校验和项保持一致了。

(3)并进行计算某些机器的字处理长度是16位的倍数,这样可以提高它的计算速度。

由于加法所具有的结合性,我们没有必要按照顺序对每个字节进行累加。

相反,我们可以利用这一特点对它们进行并行累加。

并行地计算校验和只是增加了每次累加的信息长度。

例如,在一个323位的机器上,我们可以一次增加4个字节,即[A,B,C,D]+’……。

计算结束后再把累加和“折叠”起来,把一个32位的数值变为16位,这样产生的新的进位也要循环累积起来。

此外,在此仍不考虑字节顺序的问题,我们可以用’[D,C,B,A]+’……或[B,A,D,C]+;……这样的顺序来计算校验和,最终再通过交换16位校验和中的字节序来得到正确的值。

这些改变顺序的方法都是为了让所有的偶数字节进入一个校验和字节,所有的奇数字节进入一个校验和字节。

3.3 示例下面将通过一个简单的例子来演示通过上述的几种方法所得到的校验和的情况16位按字节累加“正常”顺序交换顺序字节0/1:00 01 0001 0100字节2/3:f2 03 F203 03f2字节4/5:f4 f5 f4f5 f5f4字节6/7:f6 f7 f6f7 f7f6--- --- ----- -----合计1:2dc 1f0 2ddf0 1f2dcdc f0 ddf0 f2dc进位: 1 2 2 1-- -- ---- ----合计2:dd f2 ddf2 f2dd最终结果:dd f2 ddf2 dd f232位按字节累加“正常”顺序交换顺序字节0/1/2/3:0001f203 010003f2 03f20100 字节4/5/6/7:f4f5f6f7 f5f4f7f6 f7 f6 f5f4-------- -------- -------- 合计1:0f4f7e8fa 0f6f4fbe8 0fbe8f6f4 进位:0 0 0前半段:f4f7 f6f4 fbe8后半段:e8fa fbe8 f6f4----- ----- ----- 合计2:1ddf1 1f2dc 1f2dcddf1 f2dc f2dc 进位: 1 1 1---- ---- ---- 合计3:ddf2 f2dd f2dd 最终结果:ddf2 ddf2 ddf2还有一个例子是把计算工作分为两组,第二组是以奇数边界起始的。

按字节累加“正常”顺序字节0/1:00 01 0001字节2/:f2 (00) f200--- --- ----- 合计:f2 01 f201字节4/5:03 f4 03f4字节6/7:f5 f6 f5f6字节8/:f7 (00) f700--- --- ----- 合计2:1f0ea合计2:f0ea进位: 1----- 合计3:f0eb合计1:f201合计3(交换字节序):ebf0-----合计4 1ddf1合计4 ddf1进位: 1-----合计5:ddf23.4 一些编码技术可以提高校验和的计算速度(1)延迟进位法这种方法在主要的累加循环结束之后再把进位累加进和值。

其实现方式就是用32位的累加器获得16位校验和,这样溢出就产生在高16位上。

这种方法避免了累加器中进位传感器机构的设置,但是它要求的容量是原来的累加器容量的两倍,因此它更多地依赖于硬件条件。

(2)反向循环法这种方法可以减少由循环而产生的负荷,有效地展开内部的累加循环,把循环过程中的一系列加法命令复制下来。

这种技术通常可以节省大量的时间,但是程序的逻辑设计会比较复杂。

(3)合并数据拷贝法计算校验和以及读入数据都需要将数据从内存的一个位置转移到另一个位置,这样会占用内存总线的带宽,而内存总线的传输效率是提高校验和计算速度的瓶颈,尤其是对于某些机器(如一些简单的慢速的微型机)来说,这一问题尤为严重。

为了解决这个问题,可以把数据读入的过程与校验的过程合二为一,也就是在读入数据的同时计算校验和,这样就可以省去一次数据移动的过程,从而提高校验和的计算速度。

4 课程设计分析校验和的计算过程主要分为三个步骤:数据文件的输入,校验和的计算和校验结果的输出。

其中,主要的是数据的输入和校验和的计算过程。

4.1 数据的输入方式输入数据可能是以字符形式存储的,而校验和的计算则要采用数据形式,所以在从文件读取数据时,都要进行字符到数据的相互转换。

1)将读入的ASCII码转化为相应的整型变量。

if(ch>=’0’&&<=’9’)ch-=’0’;elseif(ch>=’a’&&ch<=’f’)ch=ch-‘a’+10;elseif(ch>=’A’&&ch<=’F’)ch=ch-‘A’+10;2) 在使用C++编程时直接使用16进制的方式打开输入文件。

Ifstream in(argv[1],ios::nocreate);i.setf(ios::hex);4.2 校验和的计算校验和算法是本程序的核心部分,在2.5节中我们介绍了一些相关的算法,而应用最为普遍的是端循环进位法。

端循环进位的算法如下:将数据按一定数位进行累加,最高位的进位则循环加入最低位。

待校验的数据按16位为一个单位相加,采用端循环进位,最后对所得16位的数据取反码。

因为待校验的数据是以字节方式分隔的,所以为了方便,将16位的数据分成高8位和低8位分别处理。

该算法的代码如下:图2-1给出了一个流程的参考方案。

endaroundcarry(int &highyte,int &lowbyte){while(highbyte>0xff||lowbyt化e>0xff)0 //高8位或低8位中的任何一方产生了溢出(进位){lowbyte+=(highbyte>>8); //低字节加上高字节超过8位的进位highbyte=highbutr&0xff; //清除高字节的进位highbyte+=(lowbyte>>8); //高字节加上来自低字节的进位lowbyte=lowbyte&0xff; Count//清除低字节的进}4.3 程序流程图图2-1给出了一个流程的参考方案4.4相关扩展前面我们提到,校验和还有其他一些计算方法,下面我们就来简要介绍以下利用延迟进位法进行计算的方法。

延迟进位法的算法描述:将进位累加的过程延迟到整个累加循环结束之后进行,这样可以提高计算速度。

3.1 主要的实现过程while(!infile.eof()) //判断文件是否结束,若否则对被校验的16位数据进行累加{int h, 1; //分别表示16位数据的高8位和低8位infile>>hex>>h; //从文件中读入一个16进制表示的数据,作为高8位if(infile.eof()) l=0; //若后面没有其他数据,将0作为低8位else infile>>hex>>1; //若后面还有数据,读入下一个作为低8位sum+=(h*256+l); //将组合好的16位数据累加到sum中}infile.close(); //关闭文件check_sum=short((sum&0xffff)+(sum>>16));//将32位累加和转换为16位数据//若累加过程中有向高16位的进位,则要将进位部分加到低16位上check_sum=-check_sum; //对累加和取反码5 程序代码#include<stdio.h>#include<stdlib.h>void main(int arga, char *argb[])//指针数组作为主函数参数,用于函数带参数入{//定义并初始化变量FILE *fp;char ch;unsigned char r1,r2;unsigned int count=0,checksum=0,rp=0;unsigned long int sum=0;//打开文件argb[1]if((fp=fopen("d:\\jiaoyan.txt","r"))==NULL){printf("\n\n File can't be opened");exit(1);}printf("\n\nthe type of output:data---sum\n\n");//从txt文件读取字符,并进行数据处理while(1){if((ch=etc(ft))!=EOF){count++;if(ch!=' '){if(count%12==0)printf("\n");//将字符转换成相应的整形变量if(ch>='0'&&ch<='9')ch-='0';elseif(ch>='a'&&ch<='f')ch=ch-'a'+10;elseif(ch>='A'&&ch<='F')ch=ch-'A'+10;//计算8字节数的累加值,将奇数位累加到长整形sum的15~8位,偶数位累加到低8~0位//这样就避免了数据个数为奇偶的处理操作if(count%2==1)r2=ch<<4;else{r1=ch&0x0f;rp=r2|r1;if(count%4==2)sum+=rp<<8;elseif(count%4==0)sum+=rp;printf("%x--%lx ",rp,sum);}}else{count--;}}else{break;}}//将sum由32位折合成16位if(sum>>16)checksum=(long(sum>>16)+long(sum&0x0000ffff));checksum=checksum&0x0000ffff;//结果输出printf("\n\nsum:%lx---checksum:%x",sum,checksum);printf("\n\nsource:arga=%d,\targb=%s\n",arga,argb[1]);fclose(ft);}6 运行结果与分析(运行结果是否正确,课程设计过程中出现的问题及其解决方案,可扩充的功能及设计等。

相关主题