计算机网络课程设计报告 帧封装.docx
《计算机网络课程设计报告 帧封装.docx》由会员分享,可在线阅读,更多相关《计算机网络课程设计报告 帧封装.docx(19页珍藏版)》请在冰豆网上搜索。
计算机网络课程设计报告帧封装
成绩:
课程设计报告
课程名称:
计算机网络课程设计
设计题目:
帧封装
姓名:
专业:
计算机科学与技术
班级:
计算机13-3班
学号:
计算机科学与技术学院
2016年1月1日
设计项目:
帧封装
一、选题背景
以太网这个术语通常是指由DEC、Intel和Xerox公司在1982年联合公布的一个标准,它是当今TCP/IP采用的主要的局域网技术,它采用一种称作CSMA/CD的媒体接入方法。
在TCP/IP世界中,以太网IP数据报文的封装在RFC894中定义。
以太网采用广播机制,所有与网络连接的工作站都可以看到网络上传递的数据。
通过查看包含在帧中的目标地址,确定是否进行接收或放弃。
如果证明数据确实是发给自己的,工作站将会接收数据并传递给高层协议进行处理。
以太网采用CSMA/CD(Carrier Sense Multiple Access/Collision Detection)媒体访问机制,任何工作站都可以在任何时间访问网络。
在以太网中,所有的节点共享传输介质。
如何保证传输介质有序、高效地为许多节点提供传输服务,就是以太网的介质访问控制协议要解决的问题。
帧是在数据链路层数据进行传输与交换的基本单位。
构造帧对于理解网络协议的概念、协议执行过程以及网络问题处理的一般方法具有重要的意义。
本次课程设计的目的是应用数据链路层与介质访问控制层的知识,根据数据链路层的基本原理,通过构造一个具体的Ethernet帧,从而深入理解网络协议的基本概念与网络问题处理的一般方法。
二.设计思路
数据在网络上是以很小的称为帧(Frame)的单位传输的,帧由几部分组成,不同的部分执行不同的功能。
帧通过特定的称为网络驱动程序的软件进行成型,然后通过网卡发送到网线上,通过网线到达它们的目的机器,在目的机器的一端执行相反的过程。
接收端机器的以太网卡捕获到这些帧,并告诉操作系统帧已到达,然后对其进行存储。
“帧”数据大致由两部分组成:
帧头和帧数据。
帧头包括接收方主机物理地址的定位以及其它网络信息。
帧数据区含有一个数据体。
为确保计算机能够解释数据帧中的数据,这两台计算机使用一种公用的通讯协议。
互联网使用的通讯协议简称IP,即互联网协议。
IP数据体由两部分组成:
数据体头部和数据体的数据区。
数据体头部包括IP源地址和IP目标地址,以及其它信息。
数据体的数据区包括用户数据协议(UDP),传输控制协议(TCP),还有数据包的其他信息。
这些数据包都含有附加的进程信息以及实际数据
以802.3的帧结构由六部分组成:
常用的以太网MAC帧格式用两种标准,一种是DIX Ethernet V2标准(即以太网V2标准),另一种是IEEE的802.3标准。
这里只介绍符合IEEE802.3标准的帧,其格式如上图所示。
它的组成比较简单,由6个字段组成。
接下来对这6个部分详细介绍一下。
(1)前导符:
由7字节的前同步码和1字节的帧起始定界符构成。
前同步码:
这个字段有7个字节(56位)交替出现的1和0,它的作用就是提醒接收系统有帧的到来,以及使到来的帧与计时器进行同步。
前同步码其实是在物理层添加上去的,并不是(正式的)帧的一部分。
前同步码的目标是允许物理层在接收到实际的帧起始符之前检测载波,并且与接收到的帧时序达到稳定同步。
帧起始定界符:
这个字段用1字节(10101011)作为帧开始的信号,表示一帧的开始。
最后两位是11,表示下面的字段是目的地址。
(2)目的地址(DA)48位,表示帧准备发往目的站的地址,共6个字节,可以是单址(代表单个站)、多址(代表一组站)或全地址(代表局域网上的所有站)。
当目的地址出现多址时,表示该帧被一组站同时接收,称为“组播”(Multicast)。
目的地址出现全地址时,表示该帧被局域网上所有站同时接收,称为“广播”(Broadcast),通常以DA的最高位来判断地址的类型,若第一字节最低位为“0”则表示单址,第一字节最低位为“1”则表示组播。
(3)源地址(SA)48位,表明该帧的数据是哪个网卡发的,即发送端的网卡地址。
(4)该字段是“长度/类型”。
当这个字段的值大于0X0600时(相当于十进制的1536),就表示“类型”。
这样的帧和以太网V2MAC帧完全一样。
只有当这个字段的值小于0X0600时才表示“长度”,即MAC帧的数据部分长度。
(5)数据字段最小长度必须为46字节以保证帧长至少为64字节,这意味着传输一字节信息也必须使用46字节的数据字段:
如果填入该字段的信息少于46字节,该字段的其余部分也必须进行填充。
数据字段的默认最大长度为1500字节。
(6)帧检验序列(FCS)32位冗余检验码(CRC),检验除前导、SFD和FCS以外的内容。
当发送站发出帧时,一边发送,一边逐位进行CRC检验。
最后形成一个32位CRC检验和填在帧尾FCS位置中一起在媒体上传输。
接收站接收后,从DA开始同样边接收边逐位进行CRC检验。
最后接收站形成的检验和若与帧的检验和相同,则表示媒体上传输帧未被破坏。
反之,接收站认为帧被破坏,则会通过一定的机制要求发送站重发该帧
差错检验:
在校验字段中,使用的是CRC校验。
校验的范围包括目的地址字段、源地址字段、长度字段、LLC数据字段。
循环冗余编码(CRC)是一种重要的线性分组码、编码和解码方法,具有简单、检错和纠错能力强等特点,在通信领域广泛地用于实现差错控制。
CRC校验码的检错能力很强,不仅能检查出离散错误,还能检查出突发错误。
利用CRC进行检错的过程可简单描述如下:
在发送端根据要传送的k位二进制码序列,以一定的规则产生一个校验用的r位监督码(CRC码),附在原始信息的后边,构成一个新的二进制码序列(共k+r位),然后发送出去。
在接收端,根据信息码和CRC码之间所遵循的规则进行检验,以确定传送中是否出错。
这个规则在差错控制理论中称为“生成多项式”。
循环冗余校验码的特点:
(1)CRC校验码可检测出所有单个错误。
(2)CRC校验码可检测出所有奇数位错误。
(3)CRC校验码可检测出所有双位的错误。
(4)CRC校验码可检测出所有小于、等于校验位长度的突发错误。
(5)CRC校验码可以的概率检测出长度为(K+1)位的突发错误。
三.主要问题的解决方法和关键技术
1.填充帧头部字段
要完成一次帧封装的过程,首先要完成的就是帧头部的装入,将前导码、定界符、目的地址、源地址、长度字段的相应数值写入。
长度字段的值即为要发送的数据的实际长度。
我们通过下面的方式获得长度字段:
22ifstreaminfile;
23infile.open(argv[1],ios:
:
binary);
24infile.seekg(0,ios:
:
end);
25shortlength=(short)infile.tellg();
26file.put(char(length/256));
27file.put(char(length%256));
2.填充数据字段
如果数据字段长度小于46B,填充0补足,超过1500B把超过的部分装入下一帧发送。
if(length<46)for(inti=0;i<46-length;++i)file.put(char(0x00));
3.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的结果。
(3)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)。
(4)循环冗余校验码的特点
CRC校验码的检错能力很强,不仅能检查出离散错误,还能检查出突发错误.CRC校验码具有以下的检错能力:
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位进行处理
47while(total--)
48{
49chartemp;
50file.get(temp);
51//printf("ssss");
52for(unsignedchari=(unsignedchar)0x80;i>0;i>>=1)
53{
54//printf("------nihao");
55if(crc&0x80)
56{
57crc<<=1;
58if(temp&i)crc^=0x01;
59
60crc^=0x07;
61}
62else
63{
64crc<<=1;
65if(temp&1)crc^=0x01;
66}
67}
68}
69//printf("\n------%x\n",crc);
70file.seekp(pCrc,ios:
:
beg);
相关扩展
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) 判断寄存器组的值是否等于“Magic Value”,若相等则通过,
7) 否则失败。
填充数据字段
在填充数据字段的过程中要注意的主要问题是数据字段的长度。
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;
四.程序流程图
CRC计算流程图:
五.原程序清单
1#include
2#include
3usingnamespacestd;
4intmain(intargc,char*argv[])
5{
6if(argc!
=3)
7{
8cout<<"è¯·æŒ‰ä¸€ä¸‹æ ¼å¼?
输入命令行:framerinputfileoutputfile"<9return0;
10}
11fstreamfile;
12file.open(argv[2],ios:
:
in|ios:
:
out|ios:
:
binary|ios:
:
trunc);
13for(inti=0;i<7;++i)file.put(char(0xaa));
14file.put(char(0xab));
15longpCrcS=file.tellp();
16chardst_addr[6]={char(0x00),char(0x00),char(0xe4),char(0x1a),char(0xe6),char(0x65)};
17file.write(dst_addr,sizeof(dst_addr));
18charsrc_addr[6]={char(0x00),char(0x00),char(0x80),char(0x1a),char(0xe6),char(0x65)};
19file.write(src_addr,sizeof(src_addr));
20
21
22ifstreaminfile;
23infile.open(argv[1],ios:
:
binary);
24infile.seekg(0,ios:
:
end);
25shortlength=(short)infile.tellg();
26file.put(char(length/256));
27file.put(char(length%256));
28
29char*data=newchar[length];
30infile.seekg(0,ios:
:
beg);
31infile.read(data,length);
32
33file.write(data,length);
34
35infile.close();
36deletedata;
37
38if(length<46)for(inti=0;i<46-length;++i)file.put(char(0x00));
39longpCrc=file.tellp();
40file.put(char(0x00));
41
42shorttotal=short(file.tellp())-(short)pCrcS;
43
44file.seekg(pCrcS,ios:
:
beg);
45
46unsignedcharcrc=0;
47while(total--)
48{
49chartemp;
50file.get(temp);
51//printf("ssss");
52for(unsignedchari=(unsignedchar)0x80;i>0;i>>=1)
53{
54//printf("------nihao");
55if(crc&0x80)
56{
57crc<<=1;
58if(temp&i)crc^=0x01;
59
60crc^=0x07;
61}
62else
63{
64crc<<=1;
65if(temp&1)crc^=0x01;
66}
67}
68}
69//printf("\n------%x\n",crc);
70file.seekp(pCrc,ios:
:
beg);
71file.put(crc);
72//printf("nihao");
73
74/*file.seekg(0,ios:
:
beg);
75while(!
file.eof())
76{
77chartemp;
78file.get(temp);
79cout<80}*/
81
82cout<<"帧文件"<装完�
"<83file.close();
84return0;
85}
六.程序运行结果
cmd运行界面:
输入文件:
in.txt
输出文件:
out.txt:
前7B的0xAA为前导码,之后0xAB为是帧前定界符,之后2个6B字段分别为目的地址和源地址(MAC),之后的0x00、0x0C标志数据字段长度。
之后46B为数据字段。
最后一个字节为CRC冗余校验的检验字段。
七.设计总结
最开始编程的时候,没有完全掌握好帧的七个组成部分,在进行封装的时候因为缺少了其中的长度字段,因而在执行framer.exe文件时,不能得到正确而的结果。
在这方面,最后通过细心的检查和查阅相关的资料,知道所缺的部分。
将其添加后,程序的整个部分无误。
又由于在此次的程序中,有很多函数的运用,因为对函数的运用掌握的不是很全面,在编写程序的过程中多多少少都会遇到一定程度的麻烦。
如fstream 既可以输入也可以输出,而ifstream只能进行输入。
刚开始编写的时候,将两者沦为一团,结果不能正确显示;seekg函数的运用中也遇到类似的问题。
在此次的课程设计中,我们小组做的题目是帧封装。
在最开始两天收集资料的过程中,我们查阅了很多帧的封装的知识,对帧及其封装的方法有了一定程度的了解和掌握。
从最开始对帧的一个模糊的印象到对帧的结构的七个部分的完全掌握,有了很大的收获,并且使帧的封装得以实现。
本次的课程设计为了实现帧的封装,主要是将帧的七个部分---前导码、帧前定界符、目的地址、源地址、长度字段、数据字段和校验字段,一个一个按顺序封装的,最后使得一个帧的封装得以完成。
同时,在编写程序的过程中,用到了很多的函数,这些函数的运用使得程序简便而且正确的运行出来。
为了正确的实现这些函数,我们查阅了很多相关的资料,从中获得了大量的有用的信息,收获也颇丰富。
八.参考文献
[1]谢希仁 编著.计算机网络(第6版) .北京:
电子工业出版社,2012
[2]吴宜功吴英编著.计算机网络课程设计(第2版).北京:
机械工业出版社,2012