这段时间开始复习计算机网络,看到帧封装这一节,结合以前的课程设计,就用C写了个帧封装的程序,说实话C学的确实不怎么样,实现的时候对于文件操作那部分查了好多资料,下面说说帧封装是啥情况。
学过计算机网络的都知道,数据的传输都是以固定的格式进行传输,在计算机当中是以二进制的数据进行传输,在网络通信中, “帧” 指通信中的一个数据块。但是帧在数据链路层传输的时候是有讲究的,不是随便的封装和打包就可以传输,大小有限制,最小46字节,最大1500字节所以我们必须按照这个规则来封装,具体的原因有兴趣的可以参考谢希仁的计算机网络帧碰撞检测那部分,说的很详细,这里不再多说,如果帧长度下于46字节就用数据填充,直到46B为止,并且填充的字段不加入长度字段中,如果大于1500字节那必须分为两个帧进行传输。
要进行帧封装还必须知道帧的结构,不知道结构无从谈起。结合书上说的802.3标准的帧结构给大家画出来了:(需要说明这是802.3标准的帧结构,还有其他版本的,也还有的吧前导码和定界符放在一起8B,既是64位,都一样)
前导码 | 前定界符 | 目的地址 | 源目的地址 | 长度字段 | 数据字段 | 校验字段 |
7B | 1B | 6B | 6B | 2B | 46-1500 | 4B |
CRC校验:
在校验字段中,使用的是CRC校验。校验的范围包括目的地址字段、源地址字段、长度字段、数据字段。CRC是一种重要的线性分组码、编码和解码方法,有检错和纠错能力强等特点,不仅能检查出离散错误,还能检查出突发错误。
按照书上的描述:利用CRC进行检错的过程可简单描述如下:在发送端根据要传送的m位二进制码序列,以一定的规则产生一个校验用的r位监督码(CRC码),附在原始信息的后边,构成一个新的二进制码序列(共m+r位),然后发送出去。在接收端,根据信息码和CRC码之间所遵循的规则进行检验,以确定传送中是否出错。这个规则在差错控制理论中称为“生成多项式”具体代码:
1 int statusNum = dataTotalNum; 2 while(statusNum--) { 3 char temp; 4 //读1B的数据 5 temp = fgetc(fileOut); 6 //模拟数据除的二进制除法过程 7 for(unsigned char i = (unsigned char)0x80; i > 0;i >>= 1) { 8 if(crc & 0x80) { //当前余数最高位为1,需要进行除法运算。 9 crc <<= 1; 10 //将输入数据相应位的值递补到余数末位 11 if(temp & i){ 12 crc ^= 0x01; 13 } 14 //进行除法运算,即与除数的低位相异或。 15 crc ^= 0x07; 16 }else{ 17 crc <<= 1; //crc左移位,最低位补。 18 //输入数据相应位的值递补到余数末位 19 if(temp & i) crc ^= 0x01;//将输入数据相应位的值递补到余数末位。 20 } 21 } 22 }
运算符:
这里还要说一下运算符,待会CRC校验还要用到:& >>=
1:按位与运算 按位与运算符"&"是双目运算符。其功能是参与运算的两数各对应的二进位相与。只有对应的两个二进位均为1时,结
果位才为1 ,否则为0。参与运算的数以补码方式出现。
例如:9&5可写算式如下: 00001001 (9的二进制补码)&00000101 (5的二进制补码) 00000001 (1的二进制补码)可见9&5=1。
按位与运算通常用来对某些位清0或保留某些位。例如把a 的高八位清 0 , 保留低八位, 可作 a&255 运算 ( 255 的二进制数为0000000011111111)。
2:>>是右移运算符,就是将n的二进制表示向右移位。你这里的n>>=1表示将n的二进制表示向右移动一位再赋值给n.这里的
>>=与+=,-=,*=的用法是一样的,先做运算再赋值
3:^ 二进制位异或,双目操作符如果a与b中有且仅有一个为1时,a^b的值为1,其它情况下值为0
设计方法:
首先向输出文件写入前导码、帧前定界符、目的地址、源地址和长度字段。然后读取到封装的数据文件(以2进制方式读取),填充到数据位,然后用crc计算校验字段就可以了。
问题:
这里需要有两个要解决的问题一个是文件大小的读取(不是直接得到文件的大小而是得到读取量的大小),一个是循环读取,当帧长度大于1500字节后要循环读取在封装。
第一个问题解决方法:记录读取数据块的位置,然后利用读取文件内部指针的偏移计算读取的大小。
1 //得到最后一个数据块的位置 2 lastDataPacket = ftell(fileIn);
第二个问题解决办法:先计算总文件的大小,利用fou循环以此讲数据块封装,具体的实现如下:
/** * 先把fpIn指针退回到文件结尾处。再得到文件位置指针 * 当前位置相对于文件首的偏移字节数,即可得到内容的长度 */ fseek(fileIn,0,SEEK_END); offsetNum = ftell(fileIn); //计算整1500数据包个数 int dataPacketNum = offsetNum/