3.4 课程设计分析
- 填充帧头部字段
要完成一次帧封装的过程,首先要完成的就是帧头部的装入,这一过程非常简单,只要将前导码、定界符、目的地址、源地址、长度字段的相应数值按顺序写入就可以了。其中,长度字段的值即为要发送的数据的实际长度。我们可以通过以下两种方式来获得长度字段的值。
- 方法一
while(!in.eof()) //读数据至缓冲区buf
{
in.get(a);
buf[j]=a; //通过j来记录输入数据的长度
j++;
}
- 方法二
infile.open(argv[1],ios::binary); //打开指定输入文件
infile.seekg(0,ios::end); //将文件读指针移到末尾
short length=(short)infile.tellg(); //获得位置偏移量,即为输入文件长度
file.put(char(length/256)); //将该长度写入数据长度字段(2 B)
file.put(char(length%256));
注意,上面程序的最后两行是把读到的数据长度值按逆序填入长度字段。这就涉及网络字节序的问题。
计算机数据存储有两种字节优先顺序,即高位字节优先和低位字节优先。
- 低位字节优先:低序字节存储在起始地址。
- 高位字节优先:高序字节存储在起始地址。
Internet上的数据以高位字节优先顺序在网络上传输,所以对于在机器内部以低位字节优先方式存储的数据来说,在Internet上传输数据时就需要进行转换,否则就会出现数据不一致。
下面是几个字节顺序转换函数:
- htonl():把32位值从主机字节序转换成网络字节序。
- htons():把16位值从主机字节序转换成网络字节序。
- ntohl():把32位值从网络字节序转换成主机字节序。
- ntohs():把16位值从网络字节序转换成主机字节序。
- 填充数据字段
在填充数据字段的过程中要注意的主要问题是数据字段的长度。802.3标准中规定了帧数据字段的最小长度为46 B,最大长度为1500 B。如果数据不足46 B,则需要通过填充0来补足;若数据长度超过1500 B,则将超过部分封装入下一个帧进行发送。
由于帧头部分应该包括6 B目的地址、6 B源地址字段、2 B长度字段以及4 B帧校验字段,因此帧头部分长度为18 B。前导码与帧前定界符不计入帧头长度中。那么,Ethernet帧的最小长度为64 B,最大长度为1518 B。
填充数据字段的代码如下:
if( len == 1500 ) //读满1500 B 后, 封装成一个帧并输出
{
... //封装成一个帧并输出
len = 0; //长度计数重置0
}
//如果数据的长度小于46则补0
if( len < 46 )
{
for( i = len; i < 46; i ++ )
fr.data[i] = 0x00; //在数据字段中填充0
}
data_len=len; //获得数据的实际长度放入data_len
- CRC校验
帧封装的最后一步就是对数据进行校验,并将校验结果记入帧校验字段。下面举例说明在本程序中是如何实现CRC-8校验算法的。设数据为10010010,CRC-8的生成多项式为X 8 + X 2 + X 1 + 1,即10000111。先看一下在代数学中计算CRC校验的一般算法。如果用竖式除法,计算过程如下:
10010001
100000111 (后面补8个0)
100000111
100011000
100000111
111110000
100000111
11110111
从上式可以看出,CRC编码实际上是一个循环移位的模2运算。对于CRC-8,假设有一个9位的寄存器,通过反复移位和进行CRC除法,最终该寄存器中的值去掉最高一位就应该是我们所需要的余数。
上述步骤可以用下面的流程描述:
//crc是一个9位的寄存器
把crc中的值置为0
在原始数据input后添加8个0
while(数据未处理完)
begin
if(crc首位是1)
crc=crc X0R 100000111
把crc中的值左移一位, 从input中读一位新的数据并置于crc的0位
end
crc中后8位就是经过CRC-8校验的余数。这样,我们只需要看后8位即可,因此上面流程可以简化。构造一个8位的寄存器crc,初始值为0,数据依次移入crc的0位,同时crc的7位移出。当移出的数据为1时,crc才和00000111进行XOR运算;移出的数据为0时,不做运算。每次crc中数据左移后就需要从输入数据中读入一位新的数据。由于左移时crc 0位补0,因此当读入的数据最高位为1时还需要对crc 0位进行处理(将crc与00000001异或使0位置1)。
下面给出伪代码:
//crc是一个8位的寄存器
把crc中的值置为0
在原始数据input后添加8个0
while(数据未处理完)
begin
if(crc首位是1)
crc左移1位
crc=crc X0R 00000111
else
crc左移1位
if(从input中读入的新的数据为1)
将crc 0位置1
end