一、课程设计的目的和意义 ...........................................................................................................1 一、 课程设计的内容和要求 .........................................................................................................2 二、 课程设计的相关技术 .............................................................................................................2
1.帧 ...........................................................................................................................................2 2.CRC校验 ................................................................................................................................3 三、 课程设计过程 .........................................................................................................................4
1.填充帧头部字段 ...................................................................................................................4 2.填充数据字段 .......................................................................................................................4 3.CRC校验 ................................................................................................................................5 4. 相关扩展 .............................................................................................................................5
1.比特型运算法 ...............................................................................................................5 2.字节型算法 ...................................................................................................................6 5.程序流程图: .......................................................................................................................7 6.CRC基本实现 ........................................................................................................................8 7.程序代码 ...............................................................................................................................9 8 运行结果与分析 ................................................................................................................. 11 五、 课程设计小结 ....................................................................................................................... 11
一、课程设计的目的和意义
--完整版学习资料分享----
-----WORD格式--可编辑--专业资料-----
目的:点对点信道的数据链路层的协议数据单元是帧。熟悉帧结构对于理解网络协议的概念、网络层次结构与协议执行过程具有重要意义。本课程设计的主要目的的是通过封装Ethernet帧,了解Ethernet帧中各个字段的含义和用途。
意义:帧是在数据链路层中进行数据传输的单位。让学生理解帧的每个字段的含义和用途,透彻理解网络协议的概念。
一、 课程设计的内容和要求
本次课程设计我负责的主要内容为:封装Ethernet帧中的CRC校验。
对于帧的封装:首先填充帧头部字段。其次便是填充帧的数据的字段(注意数据字段的长度)。最后便是CRC校验了。对于CRC校验,我们需要将校验结果记入帧校验字段。(其实现过程详细见课程设计过程)
根据后面介绍的IEEE802.3帧结构,编写程序将指定数据封装为Ethernet帧。
1)以命令行形式运行:
EncapFrame input_file output_file
其中,EncapFrame为程序名,input_file为输入数据文件,output_file为输出文件。
2) 输出内容:Ethernet帧的各字段内容。
二、 课程设计的相关技术 1.帧
术语“帧”来源于串行线路上的通信。其中,发送者在发送数据的前后分别添加特殊的字符,使它们成为一个帧。Ethernet从某种程度上可以被看做是机器之间的数据链路层连接。
首先我们来认识一下帧结构,EthernerV2.0规范和IEEE802.3标准中的Ethernet帧结构有一些差别,这里我们按802.3标准的帧结构进行讨论。图为帧结构图 前导码 帧前定界目的地址 源地址 长度字段 数据字校验字段 符 段 (7B) (1B) (2/6B) (2/6B) (2B) (长度(4B) 可变) 如上图所示,802.3标准的Ethernet帧结构由7部分组成。 (1) 前导码与帧前定界符字段
前导码由56位(7B)的10101010…10101010位序列组成。帧前定界符可以视为前导码的延续。1B的帧前定界符结构为10101011. 如果将前导码与帧前定界符一起看,那么在62位101010…1010位序列之后出现11。在11之后是Ethernet帧的目的地址字段。前导码与帧前定界符主要是保证接收同步,这8B接收后不需要保留,也不记入帧头长度中。 (2) 目的地址和源地址
目的地址(DA)与源地址(SA)分别表示帧的接收结点地址与发送结点的硬件地址。
在Ethernet帧中,目的地址和源地址字段长度可以是2B或6B。目前的Ethernet都使用6B长度的地址。
Ethernet帧的目的地址可以是单播地址、多播地址与广播地址,目的地址的第一位为0表示单播地址,为1表示多播地址,目的地址为全1则表示广
--完整版学习资料分享----
-----WORD格式--可编辑--专业资料-----
播地址。 (3) 长度字段
Ethernet帧用2B定义数据字段包含的字节数。协议规定,帧数据的最小长度为46B,最大长度为1500B。设置最小帧长度的目的是使每个接收结点能够有足够时间检测到冲突。 (4) 数据字段
帧数据字段的最小长度为46B。如果帧的LLC数据少于46B,则应将数据字段填充只46B。填充字符是任意的,不计入长度字段值中。 (5) 校验字段
帧校验字段(FCS)采用32位的CRC校验。校验的范围包括目的地址字段、源地址字段、长度字段、LLC数据字段。
此处,为了简便起见,采用8位的CRC校验。CRC校验的生成多项式为: G(X)=X^8+X^2+X+1
某些帧结构中还会包括帧类型字段,用来识别此帧所承载的数据的类型。当一个帧到达指定的计算机时,操作系统根据帧类型决定用哪个协议软件模块对它进行处理。自识别帧的主要优点是,可以在同一物理网络中使用多个协议而互不干扰。
2.CRC校验
循环冗余编码的编码方式。
循环冗余编码是一种重要的线性分组编码、解码和编码的方式,具有简单的检错和纠错能力。
过程:在发送端,根据要传送的k位二进制码序列,以一定的规则产生一个校验用的r位监督码(CRC码),附在原始信息的后边,构成一个新的二进制码序列(共k+r位),然后发送出去。在接收端,根据信息码和CRC码之间所遵循的规则进行检验,以确定传送中是否出错。这个规则在差错理论中称为“生成多项式”。
(1) CRC编码的代数学原理
将一个码组表示为一个多项式,码组中的各码元作为多项式的系数。设编码前的原始信息多项式为P(x),P(x)最高次幂加1等于k;生成多项式为G(x),它的最高次幂等于r;CRC多项式为R(x);编码后的带CRC的信息多项式为T(x)。
发送方编码的方法是:P(x)乘以x^r,再除以G(x),得余式即为R(x)。 接收方得解码方法是:将T(x)除以G(x),如果余数为0,则说明传输中无错误发生,否则说明传输有错误。 (2) CRC的基本实现
以CRC-8(X^8+X^2+X^1为例,它由多个移位寄存器和加法器组成。编码、解码前将各寄存器初始化为0,输入位作为最右边异或操作的输入之一。三个寄存器上的移位操作同时进行,均为左移一位,左边的寄存器的最左一位作为三个异或操作的输入之一。每次移位时,最右边的寄存器内容作为中间异或操作的输入之一,中间的寄存器的内容作为最左边异或操作输入之一,各个异或操作的结果作为与它左边那个寄存器的移入位。重复以上步骤,每输入一位就做一次移位操作,直到输入了所有要计算的数据为止。这时,这个寄存器组中的数据就是CRC-8的结果。
CRC运算通用电路方框图:
--完整版学习资料分享----
-----WORD格式--可编辑--专业资料-----
CRC的工作原理是:CRC在发送端编码和接收端校验时,都可以利用事先约定的生成多项式G(x)来得到,K位要发送的信息位可对应于一个(k-1)次多项式K(x),r位冗余位对应于一个(r-1)次多项式R(x),由r位冗余位组成的n=k+r位码对应于一个(n-1)次多项式T(x)=X^r*K(x)+R(x)。 (3) 循环冗余校验码的特点
CRC校验码的检错能力很强,不仅能检查出离散错误,还能检查出突发错误.CRC校验码具有以下的检错能力:
CRC校验码可检测出所有单个错误,所有奇数位错误,所有双位的错误,所有小于、等于校验位长度的突发错误。
三、 课程设计过程 1.填充帧头部字段
要完成一次帧封装的过程,首先要完成的是帧头部的装入,这一过程只要将前导码、定界符、目的地址、源地址、长度字段的相应数值按顺序写入就可以了。其中,长度字段的值即为要发送的数据的实际长度。有以下两种方式来获得长度字段的值。
方法一:
While(!in.eof()) {in.get(a); buf[j]=a; j++; }
方法二:
infile.open(argv[1],ios::binary); infile.seekg(0,ios::end);
short length=(short)infile.tellg(); file.put(char(length/256)); file.put(char(length%256)); 2.填充数据字段
在填充数据字段的过程中要注意的主要问题是数据字段的长度。802.3标准中规定了帧数据字段的最小长度为46B,最大长度为1500B。如果数据不足46B,则需要通过填充0来补足;若数据长度超过1500B,则将超过部分封装入下一个帧进行发送。
由于帧头部分应该包括6B目的地址、6B源地址、2B长度字段以及4B帧校验字段,因此帧头部分长度为18B。前导码与帧前定界符不计入帧头长度中。那么,Ethernet
--完整版学习资料分享----
-----WORD格式--可编辑--专业资料-----
帧的最小长度为64B,最大长度为1518B。
填充数据字段的代码如下: if(len==1500) {…
len=0; }
if(len<46)
{for(i=len;i<46;i++) fr.data[i]=0x00; }
data_len=len; 3.CRC校验
帧封装的最后一步就是对数据进行校验,并将校验结果记入帧校验字段。CRC编码实际上就是一个循环移位的模二运算。流程描述为:
把CRC中的值置为0
在原始数据input后添加8个0
while(数据未处理完) begin
if(crc首位是1)
crc=crc XOR 100000111
把crc中的值左移一位,从input中读取一位新的数据并置于crc的0位
crc中的后8位就是经过CRC-8校验的余数。这样,我们只需要看后8位即可,因此上面流程可以简化。构造一个8位的寄存器crc,初始值为0,数据依次移入crc的0位,同时crc的7位移出。当移出的数据为1时,crc才和00000111进行XOR运算;移出数据为0时,不做运算。每次crc中数据位为1时还需要对crc0位进行处理
伪代码:
while(数据未处理完) begin
if(crc的首位是1) crc左移1位
crc=crc XOR 00000111 else
crc左移1位
if(从input中读入的新的数据为1) 将crc 0位置1 end 4 相关扩展
1.比特型运算法
定义一个寄存器组,初始化为全1.依照电路图,每输入一个信息位,相当于一个时钟脉冲到来,从高到低依次移位。移位前信息位与bit0相加产生临时位,其中bit15移入临时位,bit10、bit3还要加上临时位。当全部信息位输入完成后,从寄存器组取出它们的值,这就是CRC码。
该算法的代码如下: typedef union
--完整版学习资料分享----
-----WORD格式--可编辑--专业资料-----
{u16 val; struct
{u16 bit0:1; u16 bit1:1; …
}bits; }CRCREGS
CRCRESGS regs;
void crcInitRegisters() {regs.val=0xffff; }
void crcInputBit(bit in) {bit a;
a=regs.bits.bit0^in;
regs.bits.bit0=regs.bits.bit1; regs.bits.bit1= regs.bits.bit2; regs.bits.bit2= regs.bits.bit3; regs.bits.bit3= regs.bits.bit4^a; regs.bits.bit4= regs.bits.bit5; regs.bits.bit5= regs.bits.bit6; regs.bits.bit6= regs.bits.bit7; regs.bits.bit7= regs.bits.bit8; regs.bits.bit8= regs.bits.bit9; regs.bits.bit9= regs.bits.bit10; regs.bits.bit10= regs.bits.bit11^a; regs.bits.bit11= regs.bits.bit12; regs.bits.bit12= regs.bits.bit13; regs.bits.bit13= regs.bits.bit14; regs.bits.bit14= regs.bits.bit15; regs.bits.bit15=a; }
u16 crcGetRegisters() {return regs.val;} crcInputBit(bit in) {bit a;
a=regs.bits.bit0^in; regs.val>>1;
if(a) regs.val^=0x8408; }
2.字节型算法
数字通信系统一般是对一帧数据进行CRC校验,而字节是帧的基本单位。最常用的是一种按字节查表的快速算法。该算法基于这样一个事实:计算本字节后的CRC码,等于上一字节CRC右移8位和本字节之和再与上一字节余式CRC码的低8位左移8位相加后所求得的CRC码。如果我们把8位二进制序列数的CRC全部计算出来,放在一个表里,那么编码时只要从表中查找对应的值进行处理即可。
算法如下:
--完整版学习资料分享----
-----WORD格式--可编辑--专业资料-----
1) 寄存器组初始化为全1。
2) 寄存器组向右移动一个字节。
3) 刚移出的那个字节与数据字节进行异或运算,得出一个指向值表的索引。 4) 将索引所指的表值与寄存器组做异或运算。
5) 数据指针加1,如果数据没有全部处理完,则重复步骤2. 6) 寄存器组取反,得到CRC,附加在数据之后。 验证算法:
1) 寄存器组初始化为全1.
2) 寄存器组向右移动一个字节。
3) 刚移出的那个字节与数据字节进行异或运算,得出一个指向值表的索引。 4) 将索引所指的表值与寄存器组做异或运算。
5) 数据指针加1,如果数据没有全部处理完,则重复步骤2.
6) 判断寄存器组的值是否等于“Magic Value”,若相等则通过,否则失败。
5.程序流程图:
--完整版学习资料分享----
-----WORD格式--可编辑--专业资料-----
开始以二进制、可读写方式打开输出文件写入前导码和帧前定界符获取当前文件指针写入目的地址和源地址打开输入数据文件,获得文件长度length,并将长度值写入输出文件将输入数据文件的内容填入数据字段数据字段长度>=46BN填充(46-length)字节’0’Y关闭输入数据文件添加1字节0,用于CRC计算计算CRC值,填充校验字段封装完成,关闭输出结束
6.CRC基本实现 除法电路实现CRC
--完整版学习资料分享----
-----WORD格式--可编辑--专业资料-----
+比特输入1514131211+10987654+3210
7.程序代码
#include void main(int argc,char*argv[]) { //如果输入命令行不正确,则输出提示后退出。 if(argc!=3) { cout< fstream file(argv[2],ios::out|ios::in|ios::binary|ios::trunc,0); for(int i=0;i<7;i++) file.put((char)0xaa); file.put((char)0xab);//写入B的前导码和B的帧前定界符。 char des_add[]={char(0x00),char(0x00),char(0xE4),char(0x86),char(0x3A),char(0xDC)}; file.write(des_add,6);//写入B的目的地址。 char sor_add[]={char(0x00),char(0x00),char(0x80),char(0x1A),char(0xE6),char(0x65)}; file.write(sor_add,6);//写入B的源地址。 //创建输入文件流并打开指定的输入文件,以二进制方式打开并可读。 ifstream infile(argv[1],ios::in|ios::binary,0); int length=0; infile.seekg(0,ios::end);//将读指针移到文件末尾。 length=infile.tellg();//计算指针偏移量,即为输入文件的长度。 --完整版学习资料分享---- -----WORD格式--可编辑--专业资料----- unsigned char* data=new unsigned char[length];//创建字符指针并根据文件长度初始化。 infile.seekg(0,ios::beg);//将读指针移到文件开始。 infile.read(data,length);//将文件数据读入到字符指针data中。 file.put(char(length>>8)); file.put(char(length&0xff));//将文件长度值按照逆序写入到输出文件的长度字段中。 file.write(data,length);//将data内容写入到输出文件中。 //如果输入文件长度不足B,则用补足B。 if(length<46) { for(int j=length;j<46;j++) file.put(char(0x00)); } file.put(char(0x00));//将数据字段后添加个 file.seekg(8,ios::beg);//将读指针指向目的地址字段,从此处开始CRC计算 unsigned char ch;//ch用来保存读入的字符。 unsigned char crc=char(0x00);//余数初始值为。 while(1)//进行CRC计算 { file.get(ch); if(ch==0xff)//判断是否到了文件结尾,如果是,则退出循环。 break; for(i=0;i<8;i++)//对入读入的字符的位分别处理。 { if(0x80==(crc&(0x80)))//当前余数最高位为,需要进行除法运算。 { crc=(crc<<1)&(0xff);//crc左移位,最低位补。 crc=crc|((ch&0x80)>>7);//将输入数据相应的值递补到余数末位。 crc=crc^(0x07);//进行除法运算,即与除数的低位相异或。 } else//当前余数的最高位为,不需要进行除法运算。 { crc=(crc<<1)&(0xff);//crc左移位,最低位补。 crc=crc|((ch&0x80)>>7);//将输入数据相应位的值递补到余数末位。 } ch=ch<<1;//读到的字符左移位,使数据下一位作为输入位。 } } file.clear(); --完整版学习资料分享---- -----WORD格式--可编辑--专业资料----- file.seekp(-1,ios::end);//将写指针移到输出文件的最后。 file.put(crc);//写入crc码。 file.close(); infile.close();//关闭输入文件和输出文件。 cout< 五、课程设计小结 本次课程设计主要是实现帧的封装。在本次课程设计中,我们组首先是将封装的 --完整版学习资料分享---- -----WORD格式--可编辑--专业资料----- 大致流程实现了。实现帧的封装,主要是将帧的七个部分---前导码、帧前定界符、目的地址、源地址、长度字段、数据字段和校验字段,一个一个按顺序封装的,最后使得一个帧的封装得以完成。在此同时,我们组采用分工的方式将封装帧的代码进行了编写。 在编写的过程中,我们遇到的问题有:1.我们是以文件流的形式实现的案例的输入与输出。在c语言中,我们经常采用的是freopen(“in.txt”,“r”,stdin);以及freopen(“out.txt”,“w”,stdout);这两个语句使得scanf从文件in.txt读入,printf写入文件out.txt。然而在此程序中,我们可以采用的是文件流。用fstream创建文件流和打开文件,这是与我们习惯不同的一个地方。2.对于CRC的计算过程:我们采用的是模拟数据除以100000111的二进制除法过程。当当前余数最高位为1,需要作除法运算,当当前余数最高位为0,我们需要不要做除法运算。 此外,对于本次课程设计,我觉得我收获了:帧结构对于网络协议的重要性,以及我们不仅能够在理论上对帧进行封装,而且实现了程序对帧的封装。我们了解到了Ethernet帧中的每个字段(前导码、帧前定界符、目的地址、源地址、长度字段、数据字段、校验字段)的含义和用途。 --完整版学习资料分享---- 因篇幅问题不能全部显示,请点此查看更多更全内容