欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

《计算机网络课程设计(第2版)》——3.4节课程设计分析

程序员文章站 2024-02-12 10:49:25
...

3.4 课程设计分析

  1. 填充帧头部字段
    要完成一次帧封装的过程,首先要完成的就是帧头部的装入,这一过程非常简单,只要将前导码、定界符、目的地址、源地址、长度字段的相应数值按顺序写入就可以了。其中,长度字段的值即为要发送的数据的实际长度。我们可以通过以下两种方式来获得长度字段的值。
  • 方法一
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位值从网络字节序转换成主机字节序。
  1. 填充数据字段
    在填充数据字段的过程中要注意的主要问题是数据字段的长度。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
  1. 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