封装Ethernet帧课程设计.docx
- 文档编号:10327518
- 上传时间:2023-02-10
- 格式:DOCX
- 页数:15
- 大小:58.49KB
封装Ethernet帧课程设计.docx
《封装Ethernet帧课程设计.docx》由会员分享,可在线阅读,更多相关《封装Ethernet帧课程设计.docx(15页珍藏版)》请在冰豆网上搜索。
封装Ethernet帧课程设计
1.课程设计目的..............................5
2.课程设计要求.............................5
3.相关知识..................................5
4.课程设计分析..............................8
5.相关扩展.................................10
6.程序代码..................................14
7.运行结果与分析............................16
8.参考文献..................................17
1课程设计目的
帧是在数据链路层中进行数据传输的基本单位。
熟悉帧结构对于理解网络协议的概念、网络层次结构与协议执行过程具有重要的意义。
本课程设计的主要目的是通过封装Ethernet帧,了解Ethernet帧中各个字段的含义与用途。
2课程设计要求
根据后面介绍的IEEE802.3帧结构,编写程序将指定数据封装为Ethernet帧。
1)以命令行形式运行:
EncapFrameinput_fileoutput_file
其中,EncapFrame为程序名,input_file为输入数据文件,output_file为输出文件。
2)输出内容:
Ethernet帧的各字段内容。
3相关知识
1.帧
术语“帧”来源于串行线路上的通信。
其中,发送者在发送数据的前后分别添加特殊的字符,使它们成为一个帧。
Ethernet从某种程度上可以被看做是机器之间的数据链路层连接。
首先我们来认识一下帧结构,EthernerV2.0规范和IEEE802.3标准中的Ethernet帧结构有一些差别,这里我们按802.3标准的帧结构进行讨论。
图为帧结构图
前导码
帧前定界符
目的地址
源地址
长度字段
数据字段
校验字段
(7B)
(1B)
(2/6B)
(2/6B)
(2B)
(长度可变)
(4B)
图1.帧结构图
如上图所示,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则表示广播地址。
(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码之间所遵循的规则进行检验,以确定传送中是否出错。
(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的工作原理是:
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校验码可检测出所有单个错误,所有奇数位错误,所有双位的错误,所有小于、等于校验位长度的突发错误。
4课程设计分析
1.填充帧头部字段
要完成一次帧封装的过程,首先要完成的是帧头部的装入,这一过程只要将前导码、定界符、目的地址、源地址、长度字段的相应数值按顺序写入就可以了。
其中,长度字段的值即为要发送的数据的实际长度。
有以下两种方式来获得长度字段的值。
方法一:
While(!
in.eof())
{in.get(a);
buf[j]=a;
j++;
}
方法二:
infile.open(argv[1],ios:
:
binary);
infile.seekg(0,ios:
:
end);
shortlength=(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帧的最小长度为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=crcXOR100000111
把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=crcXOR00000111
else
crc左移1位
if(从input中读入的新的数据为1)
将crc0位置1
end
5相关扩展
1.比特型运算法
定义一个寄存器组,初始化为全1.依照电路图,每输入一个信息位,相当于一个时钟脉冲到来,从高到低依次移位。
移位前信息位与bit0相加产生临时位,其中bit15移入临时位,bit10、bit3还要加上临时位。
当全部信息位输入完成后,从寄存器组取出它们的值,这就是CRC码。
该算法的代码如下:
typedefunion
{u16val;
struct
{u16bit0:
1;
u16bit1:
1;
…
}bits;
}CRCREGS
CRCRESGSregs;
voidcrcInitRegisters()
{regs.val=0xffff;
}
voidcrcInputBit(bitin)
{bita;
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;
}
u16crcGetRegisters()
{returnregs.val;}
crcInputBit(bitin)
{bita;
a=regs.bits.bit0^in;
regs.val>>1;
if(a)regs.val^=0x8408;
}
2.字节型算法
数字通信系统一般是对一帧数据进行CRC校验,而字节是帧的基本单位。
最常用的是一种按字节查表的快速算法。
该算法基于这样一个事实:
计算本字节后的CRC码,等于上一字节CRC右移8位和本字节之和再与上一字节余式CRC码的低8位左移8位相加后所求得的CRC码。
如果我们把8位二进制序列数的CRC全部计算出来,放在一个表里,那么编码时只要从表中查找对应的值进行处理即可。
算法如下:
1)寄存器组初始化为全1。
2)寄存器组向右移动一个字节。
3)刚移出的那个字节与数据字节进行异或运算,得出一个指向值表的索引。
4)将索引所指的表值与寄存器组做异或运算。
5)数据指针加1,如果数据没有全部处理完,则重复步骤2.
6)寄存器组取反,得到CRC,附加在数据之后。
验证算法:
1)寄存器组初始化为全1.
2)寄存器组向右移动一个字节。
3)刚移出的那个字节与数据字节进行异或运算,得出一个指向值表的索引。
4)将索引所指的表值与寄存器组做异或运算。
5)数据指针加1,如果数据没有全部处理完,则重复步骤2.
6)判断寄存器组的值是否等于“MagicValue”,若相等则通过,
7)否则失败。
图2程序流程图:
图3.CRC计算流程图
6程序代码
#include
#include
voidmain(intargc,char*argv[])
{
if(argc!
=3)
{
cout<<"请按以下格式输入命令行:
framerinputfileoutputfile"< return; } fstreamfile; file.open(argv[2],ios: : in|ios: : out|ios: : binary|ios: : trunc); for(inti=0;i<7;i++)file.put(char(0xaa)); file.put(char(0xab)); longpCrcs=file.tellp(); chardst_addr[6]={char(0x00),char(0x00),char(0x80),char(0x1a),char(0xe6),char(0x65)}; file.write(dst_addr,sizeof(dst_addr)); ifstreaminfile; infile.open(argv[1],ios: : binary); infile.seekg(0,ios: : end); shortlength=(short)infile.tellg(); file.put(char(length/256)); file.put(char(length%256)); char*data=newchar[length]; infile.seekg(0,ios: : beg); infile.read(data,length); infile.close(); deletedata; if(length<46)for(inti=0;i<46-length;i++);file.put(char(0x00)); longpCrc=file.tellp(); file.put(char(0x00)); shorttotal=short(file.tellp())-(short)pCrcs; file.seekg(pCrcs,ios: : beg); unsignedcharcrc=0; while(total--) { unsignedchartemp; file.get(temp); for(unsignedchari=(unsignedchar)0x80;i>0;i>>=1) { if(crc&0x80) { crc<<=1; if(temp&i)crc^=0x01; crc^=0x07; } else { crc<<=1; if(temp&i)crc^=0x01; } } } file.seekg(pCrc,ios: : beg); file.put(crc); while(! file.eof()) { unsignedchartemp; file.get(temp); cout< } cout<<"帧文件"< } 7运行结果与分析 图4.运行结果图1 图5.运行结果图2 实验小结: 实现帧的封装,主要是将帧的七个部分---前导码、帧前定界符、目的地址、源地址、长度字段、数据字段和校验字段,一个一个按顺序封装的,最后使得一个帧的封装得以完成。 同时,在编写程序的过程中,用到了很多的函数,这些函数的运用使得程序简便而且正确的运行出来。 8参考文献 [1]谢希仁编著.计算机网络(第6版).北京: 电子工业出版社,2012 [2]吴宜功吴英编著.计算机网络课程设计(第2版).北京: 机械工业出版社,2012
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 封装 Ethernet 课程设计
![提示](https://static.bdocx.com/images/bang_tan.gif)