课程设计
课程设计任务书
学生姓名: 专业班级: 班
指导教师: 工作单位: 计算机学院
题目一: 帧封装
初始条件:
(1)学习相关知识
(2)C/C++/VC/VB/JAVA语言
(3)PC机一台
要求完成的主要任务: (包括课程设计工作量及其技术要求,以及说明书撰写等具体要求)
编写程序,根据给出的原始数据,组装一个IEEE802.3格式的帧(题目默认的输入文件为二进制原始数据(文件名为input1和input2))。
1)要求程序为命令行程序。比如,可执行文件名为framer.exe,则命令行形式如下:
framer inputfile outputfile
其中,inputfile为原始数据文件,outputfile为输出结果。使用操作系统、语言、编程环境不限,但在报告中必须注明。
2)输出:对应input1和input2的结果分别为output1和output2。
时间安排:
第一、二天:查阅资料,学习算法
第三、四天:编程调试
第五天:书写报告
指导教师签名: 年 月 日
系主任(或责任教师)签名: 年 月 日
目录
1. 开发环境与工具.... 4
2. 设计思想.... 4
2.1 IEEE802.3帧结构.... 4
2.2 错检测.... 5
3. 算法结构.... 6
3.1 命令收集部分.... 6
3.2 添加前导符.... 7
3.3 添加目的地址及源地址.... 7
3.4 长度及数据字段.... 7
3.5 帧检验序列.... 8
4. 源程序及执行代码说明.... 9
4.1 源程序.... 9
5. 调试结果.... 13
6. 心得体会.... 15
帧封装
1. 开发环境与工具
本次课程设计用语言在中模拟帧封装行为,操作系统采用,环境使用版本。
2. 设计思想
2.1 IEEE802.3帧结构
数据在网络上是以很小的称为帧(Frame)的单位传输的,帧由几部分组成,不同的部分执行不同的功能。帧通过特定的称为网络驱动程序的软件进行成型,然后通过网卡发送到网线上,通过网线到达它们的目的机器,在目的机器的一端执行相反的过程。接收端机器的以太网卡捕获到这些帧,并告诉操作系统帧已到达,然后对其进行存储。
“帧”数据大致由两部分组成:帧头和帧数据。帧头包括接收方主机物理地址的定位以及其它网络信息。帧数据区含有一个数据体。为确保计算机能够解释数据帧中的数据,这两台计算机使用一种公用的通讯协议。互联网使用的通讯协议简称IP,即互联网协议。IP数据体由两部分组成:数据体头部和数据体的数据区。数据体头部包括IP源地址和IP目标地址,以及其它信息。数据体的数据区包括用户数据协议(UDP),传输控制协议(TCP),还有数据包的其他信息。这些数据包都含有附加的进程信息以及实际数据。
图2-1 IEEE802.3帧结构
常用的以太网MAC帧格式用两种标准,一种是DIX Ethernet V2标准(即以太网V2标准),另一种是IEEE的802.3标准。这里只介绍符合IEEE802.3标准的帧,其格式如图2-1所示。
它的组成比较简单,由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),就表示“类型”。这样的帧和以太网V2 MAC帧完全一样。只有当这个字段的值小于0X0600时才表示“长度”,即MAC帧的数据部分长度。
(5)数据字段的最小长度必须为46字节以保证帧长至少为64字节,这意味着传输一字节信息也必须使用46字节的数据字段:如果填入该字段的信息少于46字节,该字段的其余部分也必须进行填充。数据字段的默认最大长度为1500字节。
(6)帧检验序列(FCS)是32位冗余检验码(CRC),检验除前导、SFD和FCS以外的内容。当发送站发出帧时,一边发送,一边逐位进行CRC检验。最后形成一个32位CRC检验和填在帧尾FCS位置中一起在媒体上传输。接收站接收后,从DA开始同样边接收边逐位进行CRC检验。最后接收站形成的检验和若与帧的检验和相同,则表示媒体上传输帧未被破坏。反之,接收站认为帧被破坏,则会通过一定的机制要求发送站重发该帧。
2.2 错检测
校验字段中,使用的是CRC校验。校验的范围包括目的地址字段、源地址字段、长度字段、LLC数据字段。
循环冗余编码(CRC)是一种重要的线性分组码、编码和解码方法,具有简单、检错和纠错能力强等特点,在通信领域广泛地用于实现差错控制。CRC校验码的检错能力很强,不仅能检查出离散错误,还能检查出突发错误。
利用CRC进行检错的过程可简单描述如下:在发送端根据要传送的k位二进制码序列,以一定的规则产生一个校验用的r位监督码(CRC码),附在原始信息的后边,构成一个新的二进制码序列(共k+r位),然后发送出去。在接收端,根据信息码和CRC码之间所遵循的规则进行检验,以确定传送中是否出错。这个规则在差错控制理论中称为“生成多项式”。
循环冗余校验码的特点:
(1)CRC校验码可检测出所有单个错误。
(2)CRC校验码可检测出所有奇数位错误。
(3)CRC校验码可检测出所有双位的错误。
(4)CRC校验码可检测出所有小于、等于校验位长度的突发错误。
(5)CRC校验码可以 的概率检测出长度为(K+1)位的突发错误。
3. 算法结构
1
2
3
4
5
3.1 命令收集部分
要求中指出程序为命令行程序,即以” ”的形式使用程序。故程序开始前需要加一个命令收集功能。使用者输入一串指令后,程序需从中找到输入文件和输出文件的名字,即将指令按空格将其分割并收集这三个部分。流程图如图3-1所示:
3.2 添加前导符
前导符包括7字节的前发送码和1字节的帧起始定界符。只需在最前面加上7个十六进制数”AA”和1个”AB”即可。
3.3 添加目的地址及源地址
我们知道,目的机器的硬件地址是通过ARP协议得到的,这需要发送ARP请求包才能得到,为了简化程序的设计,突出本次设计的要点,因此将目的地址固定写成“EE:EE:EE:EE:EE:EE”。类似地,获得本机地址也需要通过一系列的函数调用,在程序中就直接使用本机的MAC地址“14:e6:e4:86:92:76”。
3.4 长度及数据字段
对于发送端来说,必须先获得数据的长度,将长度字段添加到帧中之后才能再添加数据字段,这就限定了必须访问输入文件两次,第一次用于获得文件长度,第二次用于封装帧。当然在进行CRC计算的时候有一些地方可以优化。
本程序的文件是通过FileInputStream进行读入,通过FileOutputStream进行输出。
3.5 帧检验序列
计算FCS是本程序最困难的部分。算法描述如下:
(1)输入需要检验的序列M,以及发送方与接收方约定好的除数P,并初始化余数R为0,若P有n位,则R有n – 1位;
(2)对序列M中的每一位(记为b)进行步骤(3)。结束后R即为FCS。
(3)将R左移1位,并将b添加到R的最低位,判断R的最高位,如果是0,则继续(3),如果是1,则将R和P进行按位与操作,结果保存到R中。
图3- 2求解FCS流程图
相应的流程图如图3-2所示。
4. 源程序及执行代码说明
4.1 源程序
package com.Frame;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;
publicclass testframer2 {
publicstaticvoid main(String[] args) throws IOException {
/*
* if (args.length < 2) { System.out.println(" argument error!");
* return; }
*/
System.out.println("Plase input the order(framer inputfile outfile)");
Scanner input =new Scanner(System.in);
String order=input.nextLine();
String ss[];
ss = order.split(" ");
String first;
String infile;
String outfile;
int i = 0;
while(ss[i].trim().isEmpty())
{
i++;
}
first = ss[i++];
if(!first.equals("framer")) //judge the first word
{
System.out.println("order error!");
return;
}
while(ss[i].trim().isEmpty())
{
i++;
}
infile = ss[i++];
while(ss[i].trim().isEmpty())
{
i++;
}
outfile = ss[i];
FileInputStream fin = null;
FileOutputStream fout = null;
try {
fin = new FileInputStream(infile);
fout = new FileOutputStream(outfile);
} catch (IOException e) {
System.out.println("NOT FOUND THE INPUT FILE!");
return;
}
appendPrefix();// add the preamble
appendAddress(); // add the destination address and the source address
appendData(fin, fout); // add the data and FCS
fin.close();
fout.close();
System.out.println("Finished");
}
/**
*
* add the preamble
* @return
*/
publicstaticboolean appendPrefix() {
// add 7 "AA"
for (int i = 0; i < 7; ++i) {
tmp.add(0XAA);
}
// the 8th is AB
tmp.add(0XAB);
returntrue;
}
/**
*
* add the destination address and the source address
* @return
*/
publicstaticboolean appendAddress() {
// the destination address has 6 "EE"
for (int i = 0; i < 6; ++i) {
tmp.add(0XEE);
}
// the source address is my MAC address "14:e6:e4:86:92:76"
tmp.add(0X14);
tmp.add(0XE6);
tmp.add(0XE4);
tmp.add(0X86);
tmp.add(0X92);
tmp.add(0X76);
returntrue;
}
/**
* add the data and FCS
*
* @param in
*
* @param out
*
* @return
*/
publicstaticboolean appendData(InputStream in, OutputStream out) {
int[] data = newint[MAX_SIZE];
int size = 0; // the size of data
int curByte = 0; // the current byte
try {
while (size < MAX_SIZE && (curByte = in.read()) != -1) {
data[size++] = curByte;
}
} catch (IOException e1) {
e1.printStackTrace();
returnfalse;
}
// add the size of data into frame
tmp.add(size >> 8);
tmp.add(size);
// add the data
for (int i = 0; data[i] != -1 && i < size; ++i) {
tmp.add(data[i]);
}
// filling "00" if the size of date if shorter than 46
if (size < MIN_SIZE) {
for (int i = 0; i < MIN_SIZE - size; ++i) {
tmp.add(FILL_BYTE);
}
}
// calculate the FCS
int R = 0; // the remainder
try {
for (int b : tmp) {
//
out.write(b);
R = nextR(R, b);
}
} catch (IOException e) {
e.printStackTrace();
returnfalse;
}
try {
// add the FCS
out.write(R >> 24);
out.write(R >> 16);
out.write(R >> 8);
out.write(R);
} catch (IOException e) {
e.printStackTrace();
returnfalse;
}
returntrue;
}
publicstaticint nextR(int currentR, int curByte) {
// calculate the FCS
int mask = 0X80;
int curBit = 0;
for (int i = 0; i < 8; ++i, mask >>= 1) {
curBit = (curByte & mask) == 0 ? 0X0 : 0X1;
currentR <<= 1;
currentR += curBit;
if ((currentR & MASK_HIGH) != 0) {
currentR = currentR ^ P;
}
}
return currentR;
}
//
publicstaticfinalintMAX_SIZE = 1500;
// the maximum size of data
publicstaticfinalintMIN_SIZE = 46;
// the minimum size of data
publicstaticfinalintFILL_BYTE = 0X00;
// the filling byte "00"
publicstaticfinalintP = 0X12345678;
//
publicstaticfinalintMASK_HIGH = 0X8000;
privatestatic List<Integer> tmp = new LinkedList<Integer>();
}
5. 调试结果
为了演示需要,首先新建一个文本文件,内容为“Hello World! Give me five!”(不含引号),如图5-1所示。用文本文件的一个好处是可以方便的检测输出文件(即帧的格式)是否正确。
图5- 1 input1文件内容
接下来将源程序进行编译和运行。单击中的按钮即可,然后进入操作界面,接着进入键入指令阶段,按照提示键入”framer input1 output1”如图5-2所示。
图5- 2操作演示
若键入指令方式与要求不符将会报错,如图5-3所示。
得到输出文件内容如图5-4所示,因文件为二进制文件,所以借用了一个特殊的第三方软件来打开它。
由上图可知,前8个字节是约定好的前导码,正确的。接下来6个字节是目的地址,和前面说明的也一样。然后是源地址,即本机的MAC地址,也是正确的。然后是数据长度,“Hello World! Give me five!”刚好是26个字符,所以也是正确的。然后是数据内容,后面的一串零是为了将其长度补充到46,是正确的。最后四个字节是FCS码。
6. 心得体会
计算机网络根据OSI模型可分为五层,分别是:应用层、传输层、网络层、数据链路层、物理层。物理层于硬件关系很大并不是我们的重点,那么数据链路层自然而然的就成为了我们的重点基础,而帧恰好是数据链路层的核心内容。
帧由几部分组成,不同的部分执行不同的功能。帧通过特定的称为网络驱动程序的软件进行成型,然后通过网卡发送到网线上,通过网线到达它们的目的机器,在目的机器的一端执行相反的过程。接收端机器的以太网卡捕获到这些帧,并告诉操作系统帧已到达,然后对其进行存储。就是在这个传输和接收的过程中,嗅探器会带来安全方面的问题 。
“帧”数据由两部分组成:帧头和帧数据。帧头包括接收方主机物理地址的定位以及其它网络信息。帧数据区含有一个数据体。为确保计算机能够解释数据帧中的数据,这两台计算机使用一种公用的通讯协议。互联网使用的通讯协议简称IP,即互联网协议。IP数据体由两部分组成:数据体头部和数据体的数据区。数据体头部包括IP源地址和IP目标地址,以及其它信息。数据体的数据区包括用户数据协议(UDP),传输控制协议(TCP),还有数据包的其他信息。这些数据包都含有附加的进程信息以及实际数据。
此次的课程设计是组装一个IEEE802.3格式的帧,这是国际标准的封装。做了一遍后感觉对帧的概念清晰了很多,对它的封装方式也了解了很多。最后实现了封装,对专业课的兴趣增加了很多,对计算机网络也更加有信心了。
本次是采用语言来实现封装的,所以我对和的使用更加熟练了。尤其是对中流的概念更加清晰了,对中的数据结构也熟悉了很多。同时也理解了自己动手丰衣足食的道理。
本科生课程设计成绩评定表
班级: 姓名: 学号:
注:最终成绩以五级分制记。优(90-100分)、良(80-89分)、中(70-79分)、
及格(60-69分)、60分以下为不及格
指导教师签名:
201 4年 01月11日