Ethernet帧结构解析汇报.docx
《Ethernet帧结构解析汇报.docx》由会员分享,可在线阅读,更多相关《Ethernet帧结构解析汇报.docx(17页珍藏版)》请在冰豆网上搜索。
Ethernet帧结构解析汇报
实验一Ethernet帧结构解析
一.需求分析
实验目的:
(1)掌握Ethernet帧各个字段的含义与帧接收过程;
(2)掌握Ethernet帧解析软件设计与编程方法;
(3)掌握Ethernet帧CRC校验算法原理与软件实现方法。
实验任务:
(1)捕捉任何主机发出的Ethernet802.3格式的帧和DIXEthernetV2(即EthernetII)格式的帧并进行分析。
(2)捕捉并分析局域网上的所有ethernetbroadcast帧进行分析。
(3)捕捉局域网上的所有ethernetmulticast帧进行分析。
实验环境:
安装好Windows2000Server操作系统+Ethereal的计算机
实验时间;2节课
二.概要设计
1.原理概述:
以太网这个术语通常是指由DEC,Intel和Xerox公司在1982年联合公布的一个标准,它是当今TCP/IP采用的主要的局域网技术,它采用一种称作CSMA/CD的媒体接入方法。
几年后,IEEE802委员会公布了一个稍有不同的标准集,其中802.3针对整个CSMA/CD网络,802.4针对令牌总线网络,802.5针对令牌环网络;此三种帧的通用部分由802.2标准来定义,也就是我们熟悉的802网络共有的逻辑链路控制(LLC)。
以太网帧是OSI参考模型数据链路层的封装,网络层的数据包被加上帧头和帧尾,构成可由数据链路层识别的数据帧。
虽然帧头和帧尾所用的字节数是固定不变的,但根据被封装数据包大小的不同,以太网帧的长度也随之变化,变化的范围是64-1518字节(不包括8字节的前导字)。
帧格式EthernetII和IEEE802.3的帧格式分别如下。
EthernetrII帧格式:
----------------------------------------------------------------------------------------------
|前序|目的地址|源地址|类型|数据
|FCS|
----------------------------------------------------------------------------------------------
|8byte|6byte|6byte|2byte|46~1500byte|4byte|
IEEE802.3一般帧格式
-----------------------------------------------------------------------------------------------------------|前序|帧起始定界符|目的地址|源地址|长度|数据|FCS|-----------------------------------------------------------------------------------------------------------|7byte|1byte|2/6byte|2/6byte|2byte|46~1500byte|4byte|EthernetII和IEEE802.3的帧格式比较类似,主要的不同点在于前者定义的2字节的类型,而后者定义的是2字节的长度;所幸的是,后者定义的有效长度值与前者定义的有效类型值无一相同,这样就容易区分两种帧格式
2程序流程图:
三.详细设计:
1.CRC校验部分设计:
为了对以太网帧的对错进行检验,需要设计CRC校验部分。
采用以为相与的方式对帧的首部相继作8位CRC校验
输入参数:
chCurrByte低8位数据有效,记录了上一次CRC校验的余数
chNextByte低8位数据有效,记录了本次要继续校验的一个字节
传出参数:
chCurrByte低8位数据有效,记录了本次CRC校验的余数
voidcheckCRC(int&chCurrByte,intchNextByte)
{
//CRC循环:
每次调用进行8次循环,处理一个字节的数据。
for(intnMask=0x80;nMask>0;nMask>>=1)
{
if((chCurrByte&0x80)!
=0)//首位为1:
移位,并进行异或运算
{
chCurrByte<<=1;//移一位
if((chNextByte&nMask)!
=0)//补一位
{
chCurrByte|=1;
}
chCurrByte^=7;//首位已经移出,仅对低8位进行异或运算,7的二进制为0000,0111
}
else//首位为0,只移位,不进行异或运算
{
chCurrByte<<=1;//移一位
if((chNextByte&nMask)!
=0)//补一位
{
chCurrByte|=1;
}
}
}
}
2.部分变量的声明:
intnSN=1;//帧序号
intnCheck=0;//校验码
intnCurrDataOffset=22;//帧头偏移量
intnCurrDataLength=0;//数据字段长度
boolbParseCont=true;//是否继续对输入文件进行解析
intnFileEnd=0;//输入文件的长度
3.计算数据段的长度:
nCurrDataLength=
bParseCont?
//是否到达文件末尾
(file.tellg()-8-1-nCurrDataOffset):
//没到文件末尾:
下一帧头位置-前导码和定界符长度-CRC校验码长度-数据字段起始位置
(file.tellg()-1-nCurrDataOffset);//已到达文件末尾:
文件末尾位置-CRC校验码长度-数据字段起始位置
4.主函数的设计:
voidmain(intargc,char*argv[])
{
//检测命令行参数的正确性
if(argc!
=2)
{
cout<<"请以帧封装包文件为参数重新执行程序"<exit(0);
}
//检测输入文件是否存在,并可以按所需的权限和方式打开
ifstreamfile(argv[1],ios:
:
in|ios:
:
binary|ios:
:
nocreate);
if(!
file.is_open())
{
cout<<"无法打开帧封装包文件,请检查文件是否存在并且未损坏"<exit(0);
}
//变量声明及初始化
intnSN=1;//帧序号
intnCheck=0;//校验码
intnCurrDataOffset=22;//帧头偏移量
intnCurrDataLength=0;//数据字段长度
boolbParseCont=true;//是否继续对输入文件进行解析
intnFileEnd=0;//输入文件的长度
//计算输入文件的长度
file.seekg(0,ios:
:
end);//把文件指针移到文件的末尾
nFileEnd=file.tellg();//取得输入文件的长度
file.seekg(0,ios:
:
beg);//文件指针位置初始化
cout.fill('0');//显示初始化
cout.setf(ios:
:
uppercase);//以大写字母输出
//定位到输入文件中的第一个有效帧
//从文件头开始,找到第一个连续的“AA-AA-AA-AA-AA-AA-AA-AB”
while(true)
{
for(intj=0;j<7;j++)//找7个连续的0xaa
{
if(file.tellg()>=nFileEnd)//安全性检测
{
cout<<"没有找到合法的帧"<file.close();
exit(0);
}
//看当前字符是不是0xaa,如果不是,则重新寻找7个连续的0xaa
if(file.get()!
=0xaa)
{
j=-1;
}
}
if(file.tellg()>=nFileEnd)//安全性检测
{
cout<<"没有找到合法的帧"<file.close();
exit(0);
}
if(file.get()==0xab)//判断7个连续的0xaa之后是否为0xab
{
break;
}
}
//将数据字段偏移量定位在上述二进制串之后14字节处,并准备进入解析阶段
nCurrDataOffset=file.tellg()+14;
file.seekg(-8,ios:
:
cur);
//主控循环
while(bParseCont)//当仍然可以继续解析输入文件时,继续解析
{
//检测剩余文件是否可能包含完整帧头
if(file.tellg()+14>nFileEnd)
{
cout<file.close();
exit(0);
}
intc;//读入字节
inti=0;//循环控制变量
intEtherType=0;//由帧中读出的类型字段
boolbAccept=true;//是否接受该帧
//输出帧的序号
cout<\t\t"<//输出前导码,只输出,不校验
cout<\t";
for(i=0;i<7;i++)//输出格式为:
AAAAAAAAAAAAAA
{
cout.width
(2);
cout<}
//输出帧前定界符,只输出,不校验
cout<\t";
cout.width
(2);//输出格式为:
AB
cout<//输出目的地址,并校验
cout<\t";
for(i=0;i<6;i++)//输出格式为:
xx-xx-xx-xx-xx-xx
{
c=file.get();
cout.width
(2);
cout<"":
"-");
if(i==0)//第一个字节,作为“余数”等待下一个bit
{
nCheck=c;
}
else//开始校验
{
checkCRC(nCheck,c);
}
}
//输出源地址,并校验
cout<\t";
for(i=0;i<6;i++)//输出格式为:
xx-xx-xx-xx-xx-xx
{
c=file.get();
cout.width
(2);
cout<"":
"-");
checkCRC(nCheck,c);//继续校验
}
//输出类型字段,并校验
cout<\t";
cout.width
(2);
//输出类型字段的高8位
c=file.get();
cout<checkCRC(nCheck,c);//CRC校验
EtherType=c;
//输出类型字段的低8位
c=file.get();
cout.width
(2);
cout<checkCRC(nCheck,c);//CRC校验
EtherType<<=8;//转换成主机格式
EtherType|=c;
//定位下一个帧,以确定当前帧的结束位置
while(bParseCont)
{
for(inti=0;i<7;i++)//找下一个连续的7个0xaa
{
if(file.tellg()>=nFileEnd)//到文件末尾,退出循环
{
bParseCont=false;
break;
}
//看当前字符是不是0xaa,如果不是,则重新寻找7个连续的0xaa
if(file.get()!
=0xaa)
{
i=-1;
}
}
//如果直到文件结束仍没找到上述比特串,将终止主控循环的标记bParseCont置为true
bParseCont=bParseCont&&(file.tellg()//判断7个连续的0xaa之后是否为0xab
if(bParseCont&&file.get()==0xab)
{
break;
}
}
//计算数据字段的长度
nCurrDataLength=
bParseCont?
//是否到达文件末尾
(file.tellg()-8-1-nCurrDataOffset):
//没到文件末尾:
下一帧头位置-前导码和定界符长度-CRC校验码长度-数据字段起始位置
(file.tellg()-1-nCurrDataOffset);//已到达文件末尾:
文件末尾位置-CRC校验码长度-数据字段起始位置
//以文本格式数据字段,并校验
cout<\t";
unsignedchar*pData=newunsignedchar[nCurrDataLength];//创建缓冲区
file.seekg(bParseCont?
(-8-1-nCurrDataLength):
(-1-nCurrDataLength),ios:
:
cur);
file.read(pData,nCurrDataLength);//读入数据字段
intnCount=50;//每行的基本字符数量
for(i=0;i{
nCount--;
cout<checkCRC(nCheck,(int)pData[i]);//CRC校验
if(nCount<0)//换行处理
{
//将行尾的单词写完整
if(pData[i]=='')
{
cout<nCount=50;
}
//处理过长的行尾单词:
换行并使用连字符
if(nCount<-10)
{
cout<<"-"<nCount=50;
}
}
}
delete[]pData;//释放缓冲区空间
//输出CRC校验码,如果CRC校验有误,则输出正确的CRC校验码
cout<c=file.get();//读入CRC校验码
intnTmpCRC=nCheck;
checkCRC(nCheck,c);//最后一步校验
if((nCheck&0xff)==0)//CRC校验无误
{
cout.width
(2);
cout<<"(正确):
\t"<}
else//CRC校验有误
{
cout.width
(2);
cout<<"(错误):
\t"<checkCRC(nTmpCRC,0);//计算正确的CRC校验码
cout<<"\t应为:
"<bAccept=false;//将帧的接收标记置为false
}
//如果数据字段长度不足46字节或数据字段长度超过1500字节,则将帧的接收标记置为false
if(nCurrDataLength<46||nCurrDataLength>1500)
{
bAccept=false;
}
//输出帧的接收状态
cout<\t\t"<<(bAccept?
"Accept":
"Discard")<nSN++;//帧序号加1
nCurrDataOffset=file.tellg()+22;//将数据字段偏移量更新为下一帧的帧头结束位置
}
//关闭输入文件
file.close();
}
四.运行结果:
五.简明用户手册:
用户需将源程序在VC++6.0下运行成功后,将实验1.EXE放在DOS下运行,运行的同时需要输入位置参数,本例用的位置参数为input,回车即可。
六.实验总结:
这次试验,充分运用了所学的计算机网络知识,设计出了如何解析以太网帧,从而更加深刻的了解到了以太网帧的结构及其的相关问题。
其实通过这些最近的实验觉得最重要一点就是:
我们一定要自己动手,这样才能真正的学到东西。
书本知识固然重要,但我们更要学会将书本知识应用到实际的工作中。
实践中才会发现错误,也才能改进,才能达到学习的最终目的。