vs做网站需要的插件,wordpress显示备案号,网址多少钱一个,网站建设方案服务公司目录阶段目标设计描述1、帧结构2、帧定位3、差错检测4、差错控制5、流量控制6、长帧传输——分片测试情况其他想说的话阶段目标
用链路层例程代码#xff08;LnkTester.sln#xff09;设计实现链路层上点到点之间的通信过程#xff0c;具体包括#xff1a;两点之间帧同步、…
目录阶段目标设计描述1、帧结构2、帧定位3、差错检测4、差错控制5、流量控制6、长帧传输——分片测试情况其他想说的话阶段目标
用链路层例程代码LnkTester.sln设计实现链路层上点到点之间的通信过程具体包括两点之间帧同步、、差错检测、差错控制、简单的流量控制。
设计描述
本阶段主要停留在链路层对等实体之间的通信故我们设计时出于简便的测试的想法先不考虑上下之间的数据传递带来的封装问题将应用层融合为链路层。不过需要修改配置文件将PHY和APP两层的配置文件改为PHY和LNK的两层文件主要就是改一个APP层的名字没有其他需求印象中是不太需要改其他参数的。
1、帧结构
不管是帧、数据包还是什么其他的数据形式也好设计之初对于帧格式的设计一定是首尾的这是一切的基础。在计算机网络的发展史中协议的产生常常会伴随帧格式的改变。所以这是设计中的重头戏。
PS设计采用面向位填充首尾定界法
01111110000000011001…011001111110帧头定界符ACK标志位帧序号数据位CRC校验位帧尾定界符
2、帧定位
原理
帧定位采用面向位填充首尾定界法。帧头和帧尾标志固定为‘01111110’在发送方封装成帧时通过get_frame()函数将帧内连续5个1后添加一个0以便能够准确对帧进行定位。在接收方又通过读取bit流读到首尾的“01111110”来进行定界然后去除数据位中的连续5个1后的0.来还原真实数据位。U8类型char类型此处这样定义只是为了专门区别用来表示单字节数据这是指导书的说明但我自己使用的时候则感觉多把他看成是1bit数据的形式。
涉及函数
int get_frame(U8* s, int len); //发送端成帧
int locate_frame(U8* s, int len,U8* bufSend); //接收端提取帧要点
需要对于连续8位数据的读取判断首尾定界符这是简单的for循环。需要添加和提取5个1后面的0这也是数据结构中基础的移位问题要注意数据前移和后移时的到底是尾部先移动还是头部先移动。除了简单的去除5个1后的0可能要考虑因为去除CRCACK标志位和序列号时指针头的移动和len的变化问题也可以简单在向上层转发函数中考虑。
3、差错检测
原理
差错检测采用CRC-4来产生校验码紧跟数据后面其中CRC生成多项式采用固定G[5] { 1,0,0,1,1 }利用crccode函数来产生四位校验码并在接收端用crcdecode函数进行校验。校验错误则丢弃该帧等待重传。此处实际情况好像是多采用检错能力更强的CRC16此处出于简便设计和运算速度采用最短的CRC校验码
涉及函数
int crccode(U8* s, int len);
//计算s的CRC校验位采用生成多项式G[5]{10011}
bool crcdecode(U8* s, int len); //接收方校验数据要点
添加和删除校验码的移位问题以及注意改变数据的长度lenCRC的计算原理是采用模2除法区别于二进制除法
4、差错控制
原理
对于数据在信道上进行传输的过程中可能产生的误码进行差错控制设计我们采用停等协议进行差错控制虽然后续阶段的设计发现停等协议这种一发一收的方式还是不够高效但设计是最简单的其实可以尝试滑窗的GB_N和SR协议增加1位ACK标识符和4位序列由于是停等协议序号只有0000和1111ACK标志位判断当前帧是数据帧0还是确认帧1并且判断收到的是否为正确序号的帧相应确认帧序号总是为期待收到的下一帧的序列号。确认帧的数据位采用八位全111111111作为数据部分。为提高效率收方收到ACK为1的帧数据位中判断收到数据位中有超过四个1即判断收到确认帧同时序号中有三个及三个以上相同数字的即自动纠错判断帧序号。在发生差错和丢包时利用Timeout内部的重传函数将缓存下来的数据进行定时帧重传直到接收到正确的确认帧然后计时器开始变量isTimeStart停止。
涉及函数
int add_ack_seq(U8* s, int len);
//加入1位ACK标识位和4位序列号——————确认帧的ACK为1并且ACK的数据bit流部分为11111111
bool isAck(U8* s); //判断是否为确认帧
int get_ack_frame(U8* s, U8* ack_frame);
//生成s对应的确认帧帧序号为期待下一次接收到的帧序号---------------------重要变量-----------------------------超时重传--
int TickTack 0;//全局变量在Timeout()用来差错控制中的重传
bool isTimerStart false;//全局计时器启动标志--缓存区--
U8* buffer NULL;//全局的缓冲区发送前用来装载可能重传的数据
int buflen 0;//缓冲区储存的字符串长度--帧序号--
U8 SEQ[4] { 0,0,0,0 };//四位序列号为全局变量只有0000和1111停等协议中异或交替出现
要点
在数据位头部添加ACK标志位和帧序号涉及到的移位和len变化帧序号由于是采用停等协议故异或用1111和0000两个序号足矣并且多位数据可以采用前向纠错和数据位8位全1能够前向纠错同理减少重传次数提高传输效率虽然停等协议效率本来就很低。缓存区的全局变量在清空的时候建议采用提前分配一块较大的空间然后不要采用free释放的方式表示某次数据的缓存清空而采用buflen0长度清0来表示。因为在实测过程中因为前后次传输数据过程中可能会由于超时时间的数值过小导致出现连续多次释放同一块空间导致以下报错。而且反复申请和反复清空的操作本身就是一种很费资源的方式参考数据栈清空时是因为真的不会再用那一块数据了才清空的。 报错截图这个困扰了我很久网上只知道是释放了空内存后来花费很久才找到上面的解决办法
5、流量控制
在本例中对于停等协议来说其实流量控制的意义不大因为一发一收的机制本身就不会出现流量一股脑全怼进去的情况。但还是可以做流量控制可以仿照重传在Timeout函数中设置一个阈值和一个类似Ticktack的时钟变量然后当达到阈值的时候在sendtolower前sleep一定的时间达到流量控制的效果。由于当时有点摸鱼只随手写了个sleep上面的说法才应该是正确的流控
6、长帧传输——分片
这是当时自己没有做的一项拓展功能但在后面传输图片或者文件的功能实现中发现这是极其必要的。因为如果传输的数据过长会导致数据产生错误而重传的概率提高可能导致反复重传而传不过去。因此将数据进行分片多次传输减小每次传输的帧长度就有必要了。 虽然没有具体实现但后续想了一下实现思路还是比较简单可以将数据按定长分段存入一个循环队列中然后对每个小帧进行帧头和帧长的记录然后依次封装发送。可以用一个标志变量记录当发送总数据量等于从上层接收到的帧长的时候来表示一个完整的帧已经传输成功或者可以用更多的帧序号加以区分。接收方则需要按帧序号重新组装数据放入一个新的内存即可。
测试情况
1、点到点数据传输情况
发送方 接收方
2、重传情况
发送方
接收方
其他想说的话
阶段二应该是后面两个阶段的基础个人觉得阶段二主要是学会如何阅读源码然后学会如何使用已有的一些例程函数去方便我们的代码编写。然后在调试过程中最重要的就是学会看内存数据的变化这是很重要的一点能提高解决bug的效率 不过好在这一阶段的代码有老师的讲解视频可以参考所以学着参考视频放开手大胆去做克服畏难情绪好的结果才能回应这样一个好的开端