Etherent帧的封装和发送过程.docx
- 文档编号:30712309
- 上传时间:2023-08-19
- 格式:DOCX
- 页数:18
- 大小:340.89KB
Etherent帧的封装和发送过程.docx
《Etherent帧的封装和发送过程.docx》由会员分享,可在线阅读,更多相关《Etherent帧的封装和发送过程.docx(18页珍藏版)》请在冰豆网上搜索。
Etherent帧的封装和发送过程
计算机网络课程设计
实验一帧封装
实验目的:
•编写程序,根据给出的原始数据,组装一个IEEE802.3格式的帧(题目)默认的输入文件为二进制原始数据(文件名分别为input1和input2))。
•要求程序为命令行程序。
比如,可执行文件名为framer.exe,则命令行形式如下:
EncapFramerinputfileoutputfile,其中,inputfile为原始数据文件,outputfile为输出结果。
•输出:
对应input1和input2得结果分别为output1和output2。
试验要求:
•编写程序,根据给出的原始数据,组装一个IEEE802.3格式的帧(题目)默认的输入文件为二进制原始数据(文件名分别为input1和input2))。
•要求程序为命令行程序。
比如,可执行文件名为framer.exe,则命令行形式如下:
EncapFramerinputfileoutputfile,其中,inputfile为原始数据文件,outputfile为输出结果。
输出:
对应input1和input2得结果分别为output1和output2
实验设计相关知识:
帧:
来源于串行线路上的通信。
其中,发送者在发送数据的前后各添加特殊的字符,使它们成为一个帧。
Ethernet从某种程度上可以被看作是机器之间的数据链路层连接。
按802.3标准的帧结构如下表所示(802.3标准的Ethernet帧结构由7部分组成)
802.3标准的帧结构
前导码
帧前定界符
目的地址
源地址
长度字段
数据字段
校验字段
7B
1B
(2/6B)
(2/6B)
(2B)
(长度可变)
(4B)
其中,帧数据字段的最小长度为46B。
如果帧的LLC数据少于46B,则应将数据字段填充至46B。
填充字符是任意的,不计入长度字段值中。
在校验字段中,使用的是CRC校验。
校验的范围包括目的地址字段、源地址字段、长度字段、LLC数据字段。
循环冗余编码(CRC)是一种重要的线性分组码、编码和解码方法,具有简单、检错和纠错能力强等特点,在通信领域广泛地用于实现差错控制。
CRC校验码的检错能力很强,不仅能检查出离散错误,还能检查出突发错误。
利用CRC进行检错的过程可简单描述如下:
在发送端根据要传送的k位二进制码序列,以一定的规则产生一个校验用的r位监督码(CRC码),附在原始信息的后边,构成一个新的二进制码序列(共k+r位),然后发送出去。
在接收端,根据信息码和CRC码之间所遵循的规则进行检验,以确定传送中是否出错。
这个规则在差错控制理论中称为“生成多项式”。
CRC的基本实现
前导码
帧前定界符
目的地址
源地址
长度字段
数据字段
校验字段
7B
1B
(2/6B)
(2/6B)
(2B)
(长度可变)
(4B)
循环冗余校验码的特点:
(1)CRC校验码可检测出所有单个错误。
(2)CRC校验码可检测出所有奇数位错误。
(3)CRC校验码可检测出所有双位的错误(4)CRC校验码可检测出所有小于、等于校验位长度的突发错误。
(5)CRC校验码可以
的概率检测出长度为(K+1)位的突发错误
实验分析:
•填充帧头部字段
要完成一次帧封装的过程,首先要完成的就是帧头部的装入,这一过程只要将签到码、定界符、目的地址、源地址、长度字段的相应数值按顺序写入就可以了。
其中,长度字段的值即为要发送的数据的实际长度。
•填充数据字段
在填充数据字段的过程中要注意的主要问题是数据字段的长度。
802.3标准中规定了帧数据字段的最小长度为46B,最大长度为1500B。
如果数据不足46B,则需要通过填充0来补足;若数据长度超过1500B,则的大奖超过部分封装入下一个帧进行发送。
•CRC校验
帧封装的最后一步就是对数据进行校验,并将校验结果记入帧校验字段。
程序流程图:
CRC计算流程图:
程序源代码:
#include
#include
#include
voidmain(intargc,char*argv[])
{
//如果输入命令行不正确,则输出提示后退出。
if(argc!
=3)
{
cout< EncapFrameinputfileoutputfile"< exit(0); } //打开指定的输出文件,以二进制方式打开并可读可写,如文件存在,则清除其内容。 fstreamfile(argv[2],ios: : out|ios: : in|ios: : binary|ios: : trunc,0);//打开或创建一个一个供写入的文件,打开供读取的文件 for(inti=0;i<7;i++) file.put((char)0xaa); file.put((char)0xab);//写入B的前导码和B的帧前定界符。 chardes_add[]={char(0x00),char(0x00),char(0xE4),char(0x86),char(0x3A),char(0xDC)}; file.write(des_add,6);//写入B的目的地址。 charsor_add[]={char(0x00),char(0x00),char(0x80),char(0x1A),char(0xE6),char(0x65)}; file.write(sor_add,6);//写入B的源地址。 //创建输入文件流并打开指定的输入文件,以二进制方式打开并可读。 ifstreaminfile(argv[1],ios: : in|ios: : binary,0);//建立输入流语句 intlength=0; infile.seekg(0,ios: : end);//将读指针移到文件末尾。 length=infile.tellg();//计算指针偏移量,即为输入文件的长度。 unsignedchar*data=newunsignedchar[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(intj=length;j<46;j++) file.put(char(0x00)); } file.put(char(0x00));//将数据字段后添加个 file.seekg(8,ios: : beg);//将读指针指向目的地址字段,从此处开始CRC计算 unsignedcharch;//ch用来保存读入的字符。 unsignedcharcrc=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();//文件清理 file.seekp(-1,ios: : end);//将写指针移到输出文件的最后。 file.put(crc);//写入crc码。 file.close(); infile.close();//关闭输入文件和输出文件。 cout< } 运行结果: 运行结果如下所示: 执行EncapFrame.exe文件的结果如下所示: 模拟Ethernet帧的发送过程 题目: 编写程序模拟Ethernet结点的数据发送流程 设计要求: (1)用两个线程a,b来模拟Ethernet上的两台主机。 (2)用一个双字类型变量Bus来模拟总线(将其初始化为“/0”,并且总线等于“/0”时表示总线空闲)。 (3)两个子线程向总线发送自己的数据。 数据用该线程的线程信号进行模拟,发送数据用线程号和Bus的“或”操作进行模拟(即Bus=Bus|ID,ID为该线程的线程号)。 (4)每台主机须向总线成功发送10次数据,如果其中某次数据发送失败,则该线程结束。 (5)发送流程须遵循CSMA/CD。 随机延迟算法中的冲突窗口取0.005。 在数据发送成功(即Bus==ID)后,报告“IDsendsuccess”,产生冲突(即Bus! =ID)后,报告“IDsendcollision”,发送失败(即冲突计数器值为0)后报告“IDsendfailure”。 随着主机发送成功次数的增加,报告其已发送成功的次数,如“主机A发送成功次数=3”。 三、可行性分析 1.技术可行性 技术可行性分析包括: 风险分析、资源分析和技术分析。 风险分析的任务是,在给定的约束条件下,判断能否设计并实现系统所需功能和性能。 资源分析的任务是,论证是否具有系统开发所需的各类人员(管理人员和各类专业技术人员)、软件、硬件资源和工作环境等。 技术分析的任务是,论证当前的科学技术是否支持系统开发的全过程。 其中最主要的是分析技术条件是否能顺利完成开发工作,硬、软件能否满足开发者的需要等。 2.功能分析 基本功能 1.在一台计算机上实现,用多个程序或线程来模拟多个计算机 2.使用一个共享数据区来模拟总线 3.模拟实现载波监听的过程 4.模拟实现发生冲突的过程和冲突的处理机制 四.Ethernet帧的发送与接收流程 1Ethernet帧的发送流程 1)载波侦听过程。 Ethernet中每个结点利用总线发送数据,总线是每个结点共享的公共传输介质。 所以结点在发送一个帧前,必须侦听总线是否空闲。 由于Ethernet的数据采用曼彻斯特编码方式,所以可以通过判断总线电平是否跳变来确定总线是否空闲。 若总线空闲,就可以启动发送,否则继续侦听。 2)冲突检测。 在数据发送过程中,可能会产生冲突(冲突是指总线上同时出现两个或两个以上的发送信号,他们叠加后的信号波形与任何发送结点的输出波形都不相同)。 因为可能有多个主机都在侦听总线,当它们侦听到总线空闲时,就会往总线上发送数据。 所以在发送数据的过程中,也应该进行冲突检测,只要发现冲突就应该立即停止发送数据。 3)随即延迟后重发。 在检测到冲突、停止发送后,结点进行随机延迟后重发。 若发16次后还没成功,则宣告发送失败,取消该帧的发送。 随机延迟的算法一般采用截断的二进制指数退避算法。 当出现线路冲突时,如果冲突的各站点都采用同样的退避间隔时间,则很容易产生二次、三次的碰撞。 因此,要求各个站点的退避间隔时间具有差异性。 这要求通过退避算法来实现。 当一个站点发现线路忙时,要等待一个延时时间M,然后再进行侦听工作。 延时时间M由以下算法决定: M=2k*R*a。 其中a为冲突窗口值(冲突窗口为总线最大长度和电磁波在介质中传播速度比值的2倍),R为随机数,k的取值为k=min(n,16),n为该帧已被发送的次数。 图1给出了Ethernet帧的发送流程。 2Ethernet帧的接收流程 帧的接收流程大致可以分为以下三个步骤: 1)检查是否发生冲突,若发生冲突,则丢弃该帧;若没有冲突,进入下一步。 2)检查该帧的目的地址看是否可以接收该帧,若可以接收,则进入下一步。 3)检查CRC检验和LLC数据长度。 若都正确,接受该帧,否则丢弃。 图1Ethernet帧的发送流程 图2主程序流程图 五.详细设计 1.设计中的重点及难点 1)模拟冲突过程,在这个程序中不要使用任何线程同步机制。 2)若程序中不能模拟出冲突,可以在某些地方加入延时。 2.核心代码 #include #include #include HANDLEhTread1,hTread2;//线程句柄 DWORDdwThreadId1,dwThreadId2;//线程ID号 DWORDBus=0;//总线 DWORDWINAPIThreadProcA(LPVOIDlpParam) { inti=0;//发送成功次数 intCollisionCounter=11;//冲突计数器初始值为11 doublecollisionWindow=0.005;//冲突窗口值取0.005 intrandNum=rand()%3;//随机数 Loop: if(Bus==0)//总线空闲 { Bus=Bus|dwThreadId1;//模拟发送包 Sleep(12); if(Bus==dwThreadId1)//数据发送成功 { printf("%dSendSuccess\n\n",dwThreadId1);//发送成功 Bus=0;//内存清零 CollisionCounter=11;//复原冲突计数器 Sleep(rand()%10);//随机延时 i++; printf("主机a发送成功次数=%d\n\n",i); if(i<10) gotoLoop;//发送次数不够10次,开始下一次发送 } else//数据发送失败 { printf("%dSendCollision\n\n",dwThreadId1);//发生冲突 Bus=0; CollisionCounter--;//冲突计数器减1 if(CollisionCounter>0) {//随机延迟重发,延迟算法用截止二进制指数后退算法 Sleep((unsignedlong)(randNum*(int)pow(2,(CollisionCounter>10)? 10: CollisionCounter)*collisionWindow)); gotoLoop; } else { printf("%ldSendFailure\n\n",dwThreadId1);//重发次数超过16次,宣布发送失败 } } } else//总线忙 gotoLoop;//继续载波侦听 return0; } DWORDWINAPIThreadProcB(LPVOIDlpParam)//返回DWORD(32位数据)的API函数 { intj=0; intCollisionCounter=11; doublecollisionWindow=0.005; intrandNum=rand()%3; Loop: if(Bus==0) { Sleep (2); Bus=Bus|dwThreadId2; Sleep(3); if(Bus==dwThreadId2)//数据发送成功 { printf("%dSendSuccess\n\n",dwThreadId2); Bus=0; CollisionCounter=11; Sleep(rand()%10); j++; printf("主机b发送成功次数=%d\n\n",j); if(j<10) gotoLoop; } else//数据发送失败 { printf("%dSendCollision\n\n",dwThreadId2); Bus=0; CollisionCounter--; if(CollisionCounter>0) { Sleep((unsignedlong)(randNum*(int)pow(2,(CollisionCounter>10)? 10: CollisionCounter)*collisionWindow)); gotoLoop; } else { printf("%ldSendFailure\n\n",dwThreadId2); } } } else gotoLoop; return0; } intmain(intargc,char*argv[]) { hTread1=: : CreateThread(NULL,NULL,ThreadProcA,NULL,0,&dwThreadId1); //WaitForSingleObject(hTread2,INFINITE); hTread2=: : CreateThread(NULL,NULL,ThreadProcB,NULL,0,&dwThreadId2); WaitForSingleObject(hTread2,INFINITE); : : CloseHandle(hTread1); : : CloseHandle(hTread2); return0; } 七.运行结果
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Etherent 封装 发送 过程
![提示](https://static.bdocx.com/images/bang_tan.gif)