《计算机网络》 选择重传协议 实验报告
1.实验内容和实验环境描述
实验内容:
利用所学数据链路层原理,设计一个滑动窗口协议,在仿真环境下编程实现有噪音信道环境下两站点之间无差错双工通信。信道模型为8000bps 全双工卫星信道,信道传播时延270毫秒,信道误码率为10-5,信道提供字节流传输服务,网络层分组长度固定为256字节。
实验环境:
Windows7—64位操作系统PC机VC 6.0
2.协议设计
数据结构: 数据帧
+=========+========+========+===============+========+ | KIND(1) | SEQ(1) | ACK(1) | DATA(240~256) | CRC(4) | +=========+========+========+===============+========+
确认帧
+=========+========+========+ | KIND(1) | ACK(1) | CRC(4) | +=========+========+========+
否定确认帧
+=========+========+========+ | KIND(1) | ACK(1) | CRC(4) | +=========+========+========+
KIND:表示帧的类别 ACK:ACK序列号 SEQ:帧序列号 CRC:校验和
模块结构:
static inc(Uchar* a)
作用:使一个字节在0~MAX_SEQ的范围内循环自增。 参数:a,字节类型。
static between(Uchar a,Uchar b,Uchar c)
作用:判断当前帧是否落在发送/接收窗口内。
参数:a,b,c,均为字节类型,其中两个分别为窗口的上、下界,一个为帧的编号。其中,发送窗口的上界和下界分别为next_to_send和ack_expected,接收窗口的上界和下界分别为too_far和frame_expected,均定义在main函数中。 static void put_frame(unsigned char *frame, int len)
作用:为一个帧做CRC校验,填充至帧的尾部并将其递交给网络层发送。
参数:frame,字节数组,由除padding域之外的帧内容转换而来;len,整型,为帧的当前长度。
static send_frame_(Uchar fk,Uchar next_frame,Uchar frame_expected,Packet out_buf[]) 作用:构造一个帧,并将其发送。
参数:fk,字节类型,为帧的内容;next_frame,字节类型,为帧的编号;frame_expected,字节类型,为希望收到的帧的编号;out_buf,二维字节数组,为缓冲区。 int main(int argc,char *argv[])
作用:主程式,包含选择重传协议的算法流程。
参数:argc,整型,表示命令行参数的个数;argv,二维字符数组,表示参数内容。
算法流程:
Network layer Data coming ready Phy-layer ready Get packet() Count csc Find frame-end Send_data() Get_num>0 Csc==0? Y Phy ready? N Y Send frame N S_seq=frame Y Expect? Sent frame Phy_ready=1 Y Put_packet() Break break Deal with ack number In_len=1 Nbuffered (b)数据链路层:发送方和接收方都维持一个窗口,窗口内部为可以接受的序列号。接收到的数据包被缓存起来,当按正确的顺序接收完毕后再提交给网络层。ACK信息通过数据帧捎带确认的方式传递,若遇到长时间无数据帧发送,则产生ACK超时事件(ACK_TIMEOUT),主动发送空的ACK帧。若长时间未收到ACK信息,则产生数据帧超时事件(DATA_TIMEOUT),发送方自动重传未确认帧;当出现帧丢失或校验错误时,接收方会主动发送NAK帧提示发送方立即重传。 数据链路层通过物理层提供的函数来利用物理层提供的服务。通过get_packet()函数从网络层得到一个分组;当数据链路层成功接收到一个分组后,通过put_packet()函数提交给网络层。 (c)网络层:利用数据链路层提供的“可靠的分组传输”服务,在站点A与站点B之间交换长度固定为256字节的数据分组。网络层把产生的分组交付数据链路层,并接受数据链路层提交来的数据分组。 3.结果分析 (1) 描述你所实现的协议软件是否实现了有误码信道环境中无差错传输功能。 我们的协议成功实现了有误码信道环境中无差错传输功能。如果收到一个损坏帧,在尚未发送否认确定的情况下,则捎带发送否定确认。并打印错误报告。如果已发送否定确认,则只打印错误报告,不重复发送否定确认。 (2) 程序的健壮性如何,能否可靠地长时间运行。 我们的程序成功连续运行半小时以上,并取得预定效果。具有足够的健壮性。 (3) 协议参数的选取:滑动窗口的大小,重传定时器的时限,ACK 搭载定时器的时限,这些参数是 怎样确定的?根据信道特性数据,分组层分组的大小,以及你的滑动窗口机制,给出定量分析,详细列 举出选择这些参数值的具体原因。 我们物理层提供的是字节流传输服务,使用字节填充技术成帧,分组长度为256字节。 为了避免在有出错帧接收方要求重传时产生二义性,我们定义窗口大小为2^n-1,并且双方的窗口大小均为((MAX_SEQ+1)/2),这样的大小足够使用又不会有过于富余的空间浪费。滑动窗口的大小直接涉及到信道利用率和数据拥塞问题,若太大,数据发送过快将产生拥塞导致数据丢失,出错率增加,若太小则信道利用率降低,通过实验测试合适的窗口大小为16。 重传定时器时限涉及到重传的响应时间,太小会导致频繁重传,太大则重传等待时间太久,经过我们的试验测试,选取重传定时器时限定为3000毫秒,ACK 搭载定时器的时限为1000毫秒最合适。 (4)理论分析:根据所设计的滑动窗口工作机制(Go-Back-N 或者选择重传),推导出在无差错信道环境下分组层能获得的最大信道利用率;推导出在有误码条件下重传操作及时发生等理想情况下分组层能 获得的最大信道利用率。给出理论推导过程。理论推导的目的是得到信道利用率的极限数据。为了简化 有误码条件下的最大利用率推导过程,可以对问题模型进行简化,比如:假定超时重传的数据帧的回馈 ACK 帧可以 100%正确传输,但是简化问题分析的这些假设必须不会对整个结论产生较大的误差。 由于需要携带帧信息,所以最大信息利用率为 256100%96.24%,由 256442于数据链路层提供的服务为8000bps,所以每传输一个字节耗时1ms,每帧的附加信息固定为10,耗时10ms,若出现转义字符还将增加时间。 简化模型,假设信道上始终有数据需要传输。则在误码率为10的信道上,100000个比特可发送 -510000048个数据包,即每传送48个数据包将有1个出错。假设在限定时间 260*8内可以重传的该帧为正确帧,则每传送48个数据包需传送48+1+1=50次。所以信道利用率为 48*250*100%92.24%而由于程序设计原因,当一个数据包超时后,常常需 (50*26010)48*250*100%若重传 (49k)*26010要重传多次造成信道浪费。若重传k次,则信道利用率为 10次,信道利用率为78.18%。若信道误码率为10,则 -4100004.8,即大约每5个帧就 260*8有一个出错,此时在ESC/FLAG模式下平均250个字符需要两倍的传输空间即极限值510,若平均每个错帧重传10次信道利用率的极值为 (5) 实验结果分析:你的程序运行实际达到了什么样的效率,比对理论推导给出的结论,有没有差 距?给出原因。有没有改进的办法?如果没有时间把这些方法付诸编程实施,介绍你的方案。 由实验结果可以看出,窗口大小是16时信道利用率最高,与理论最大值最接近。与理论窗口最佳值一致。 在洪泛模式下,信道利用率与理论值接近。而在其他情况下负载有时较轻,所以信道利用率相比理论值较低。 (6) 存在的问题:在“表 3 性能测试记录表”中给出了几种测试方案,在测试中你的程序有没有失 败,或者,虽未失败,但表现出来的性能仍有差距,你的程序中还存在哪些问题? 实验顺利进行,每次测试得到的数据都比较接近,但和理论值相比信道利用率较低,这与信道的负载有关。 5*250*100%40.71% (6*51010)实验结果: 测试最佳窗口尺寸: 窗口大小为16, DATA_TIMER 3000, ACK_TIMER 1000 序号 命令 说明 运行时间Selective算法线路(分钟) 利用率(%) A B 30 30 1 2 datalink au datalink bu datalink a datalink b datalink afu datalink bfu datalink af datalink bf 无误码信道数据传输 站点A分组层平缓方式发出数据,站点B周期性交替发送100秒停发100秒 无误码信道,站点A和站点B的分组层都洪水式产生分组 站点A/B的分组层都洪水式产生分组 59.3 56.8 96.8 96.9 95.0 96.4 3 30 4 5 30 30 91.3 73.2 93.6 75.5 datalink af –ber 站点A/B的分组层都洪水式1e-4 产生分组,线路误码率为datalink bf –ber 10^-4 1e-4 窗口大小为8, DATA_TIMER 3000, ACK_TIMER 1000 序号 命令 说明 运行时间Selective算法线路(分钟) 利用率(%) A B 30 30 1 2 datalink au datalink bu datalink a datalink b 无误码信道数据传输 57.7 55.6 96.9 95.5 75.0 96.9 94.8 96.9 95.0 73.2 3 4 5 站点A分组层平缓方式发出数据,站点B周期性交替发送100秒停发100秒 datalink afu 无误码信道,站点A和站点datalink bfu B的分组层都洪水式产生分组 datalink af 站点A/B的分组层都洪水式datalink bf 产生分组 datalink af –ber 站点A/B的分组层都洪水式1e-4 产生分组,线路误码率为datalink bf –ber 10^-4 1e-4 30 30 30 窗口大小为32, DATA_TIMER 3000, ACK_TIMER 1000 序号 命令 说明 运行时间Selective算法线路(分钟) 利用率(%) A B 30 30 96.9 54.8 96.9 93.6 1 2 datalink au datalink bu datalink a datalink b datalink afu datalink bfu datalink af datalink bf 无误码信道数据传输 站点A分组层平缓方式发出数据,站点B周期性交替发送100秒停发100秒 无误码信道,站点A和站点B的分组层都洪水式产生分组 3 30 96.9 97.0 4 5 站点A/B的分组层都洪水式产生分组 datalink af –ber 站点A/B的分组层都洪水式1e-4 产生分组,线路误码率为datalink bf –ber 10^-4 1e-4 30 30 90.6 50.0 90.2 52.3 从测试结果比较得出,窗口最佳尺寸为16; ACK搭载定时器的时限定为1000毫秒,窗口大小为16,测试重传定时器时限 DATA_TIMER 2800,窗口大小为16, ACK_TIMER 1000 测试最佳DATA_TIMER取值 序号 命令 说明 运行时间Selective算法线路(分钟) 利用率(%) A B 30 30 1 2 datalink au datalink bu datalink a datalink b datalink afu datalink bfu 无误码信道数据传输 站点A分组层平缓方式发出数据,站点B周期性交替发送100秒停发100秒 55.3 49.6 96.9 93.9 88.7 96.9 3 4 5 无误码信道,站点A和站点B的分组层都洪水式产生分组 datalink af 站点A/B的分组层都洪水式datalink bf 产生分组 datalink af –ber 站点A/B的分组层都洪水式1e-4 产生分组,线路误码率为datalink bf –ber 10^-4 1e-4 30 30 30 86.1 69.6 88.2 70.1 DATA_TIMER 3000,窗口大小为16, ACK_TIMER 1000 序号 命令 说明 运行时间Selective算法线路(分钟) 利用率(%) A B 30 30 1 2 datalink au datalink bu datalink a datalink b datalink afu datalink bfu datalink af datalink bf 无误码信道数据传输 站点A分组层平缓方式发出数据,站点B周期性交替发送100秒停发100秒 无误码信道,站点A和站点B的分组层都洪水式产生分组 59.3 56.8 96.8 96.9 95.0 96.4 3 30 4 5 站点A/B的分组层都洪水式产生分组 datalink af –ber 站点A/B的分组层都洪水式1e-4 产生分组,线路误码率为datalink bf –ber 10^-4 1e-4 30 30 91.3 73.2 93.6 75.5 DATA_TIMER 3200,窗口大小为16, ACK_TIMER 1000 序号 命令 说明 运行时间Selective算法线路(分钟) 利用率(%) A B 30 30 1 2 datalink au datalink bu datalink a datalink b datalink afu datalink bfu 无误码信道数据传输 站点A分组层平缓方式发出数据,站点B周期性交替发送100秒停发100秒 58.0 55.8 96.9 96.8 90.3 96.9 3 4 5 无误码信道,站点A和站点B的分组层都洪水式产生分组 datalink af 站点A/B的分组层都洪水式datalink bf 产生分组 datalink af –ber 站点A/B的分组层都洪水式1e-4 产生分组,线路误码率为datalink bf –ber 10^-4 1e-4 30 30 30 89.3 63.4 90.6 68.9 DATA_TIMER 3400,窗口大小为16, ACK_TIMER 1000 序号 命令 说明 运行时间Selective算法线路(分钟) 利用率(%) A B 30 30 1 2 datalink au datalink bu datalink a datalink b datalink afu datalink bfu datalink af datalink bf 无误码信道数据传输 站点A分组层平缓方式发出数据,站点B周期性交替发送100秒停发100秒 无误码信道,站点A和站点B的分组层都洪水式产生分组 56.9 54.8 96.8 96.8 89.9 96.8 3 30 4 5 站点A/B的分组层都洪水式产生分组 datalink af –ber 站点A/B的分组层都洪水式1e-4 产生分组,线路误码率为datalink bf –ber 10^-4 1e-4 30 30 87.7 68.1 89.8 70.3 从测试结果比较得出,DATA_TIMER=3000为最佳取值 重传定时器时限定为3000毫秒,窗口大小为16,测试ACK搭载定时器的时限 ACK=1000ms 序号 命令 说明 运行时间Selective算法线路(分钟) 利用率(%) A B 30 30 1 2 datalink au datalink bu datalink a datalink b 无误码信道数据传输 59.3 56.8 96.9 96.9 95.0 96.4 3 4 5 站点A分组层平缓方式发出数据,站点B周期性交替发送100秒停发100秒 datalink afu 无误码信道,站点A和站点datalink bfu B的分组层都洪水式产生分 组 datalink af 站点A/B的分组层都洪水式datalink bf 产生分组 datalink af –ber 1e-4 站点A/B的分组层都洪水式datalink bf –ber 1e-4 产生分组,线路误码率为 10^-4 30 30 30 95.1 73.2 95.4 75.5 ACK=1100ms 序号 命令 说明 运行时间Selective算法线路(分钟) 利用率(%) 1 datalink au datalink bu 2 datalink a datalink b 3 datalink afu datalink bfu 4 datalink af datalink bf 5 datalink af –ber 1e-4 datalink bf –ber 1e-4 ACK=1200ms 序号 命令 1 datalink au datalink bu 2 datalink a datalink b 3 datalink afu datalink bfu 4 datalink af datalink bf 5 datalink af –ber 1e-4 datalink bf –ber 1e-4 无误码信道数据传输 站点A分组层平缓方式发出数据,站点B周期性交替发送100秒停发100秒 无误码信道,站点A和站点B的分组层都洪水式产生分 组 站点A/B的分组层都洪水式产生分组 站点A/B的分组层都洪水式产生分组,线路误码率为 10^-4 说明 无误码信道数据传输 站点A分组层平缓方式发出数据,站点B周期性交替发送100秒停发100秒 无误码信道,站点A和站点B的分组层都洪水式产生分 组 站点A/B的分组层都洪水式产生分组 站点A/B的分组层都洪水式产生分组,线路误码率为 10^-4 30 30 30 30 30 运行时间(分钟) 30 30 30 30 30 A B 68.4 96.9 67.6 95.6 96.9 96.9 95.1 95.0 72.5 76.3 Selective算法线路利用率(%) A B 55.9 96.9 57.1 94.9 96.9 96.9 95.2 95.1 74.5 73.3 ACK=1300ms 序号 命令 说明 运行时间Selective算法线路(分钟) 利用率(%) A B 30 30 1 2 datalink au datalink bu datalink a datalink b 无误码信道数据传输 57.0 55.8 94.8 94.9 3 4 5 站点A分组层平缓方式发出数据,站点B周期性交替发送100秒停发100秒 datalink afu 无误码信道,站点A和站点datalink bfu B的分组层都洪水式产生分 组 datalink af 站点A/B的分组层都洪水式datalink bf 产生分组 datalink af –ber 1e-4 站点A/B的分组层都洪水式datalink bf –ber 1e-4 产生分组,线路误码率为 10^-4 30 97.0 96.8 30 30 95.1 71.4 95.0 74.4 从测试结果比较得出,最佳ACK搭载定时器的时限为1100ms 实验截图:(最佳参数) DATA_TIMER 3000,窗口大小为16, ACK_TIMER 1100 datalink au datalink bu datalink a datalink b datalink afu datalink bfu datalink af datalink bf datalink af –ber 1e-4 datalink bf –ber 1e-4 4.研究和探索的问题 1.CRC 校验能力 CRC校验码的检错能力很强,它除了能检查出离散错外,还能检查出突发错,CRC校验码具有以下检错能力:CRC校验码能检查出全部单个错;CRC校验码能检查出全部离散的二位错;CRC校验码能检查出全部奇数个错;CRC校验码能检查出全部长度小于或等于K位的突发错;CRC校验码能以[1-(1/2)K-1]的概率检查出长度为(K+1)位的突发错。 2.由于本次试验过程的误码信道是一个比较固定的误码率,而在实际生活当中的误码率不是稳定的,可能会因为传输环境的不同,使得他的误码率波动比较大的,例如,下雨天和晴天,高噪声和低噪声的情况,传输的距离也是影响因素。对于这种动态的误码率的通信过程,可能需要其他的一些参数来控制基本参数值(窗口大小,重传时间等等)来完成。 3.get_ms()如何实现 C语言的time.h当中提供了一些关于时间操作的函数可以实现get_ms()函数。可以利用的函数有clock()函数原型为:clock_t clock() 该函数返回程序开始执行后占用的处理器时间,如果无法获得占用时间则返回-1。 因为我们计时的起点并不是程序开始之时,而是开始通信之时,所以需要一个静态变量start_time来记录通信起始的时间。然后在每次调用get_ms()后,获取当前的时间current_time。然后再返回start_time-current_time即可。 4.对等协议实体之间的流量控制 在我们设计的协议当中,流量的控制主要通过接收窗口,发送窗口还有确认机制来实现。因为有窗口大小的限制,发送方不会一次性发送过多信息导致接收方被信息洪流所淹没,导致信息丢失。这样可能会导致信道的利用率降低,但是如果合理的设计窗口大小,依然可以达到较高的信号利用率。 5.实验总结和心得体会 (1) 完成本次实验的实际上机调试时间是多少? 由于其他课业任务较多,日程安排紧张,完成本次试验代码的编写大约用了一周,每天晚上大约抽出1-2小时的时间。其中很大一部分时间是在程序框架的确定和debug.在这之后又花了5天,每晚1-2小时的时间用于测试协议参数的选取等问题。 (2) 编程工具方面遇到了哪些问题?包括Windows环境和VC软件的安装问题。 这方面进展十分顺利。 (3) 编程语言方面遇到了哪些问题?包括C语言使用和对C语言操控能力上的问题。 由于我们学习使用C语言时间较长,运用起来并没有什么阻碍。 (4) 协议方面遇到了哪些问题?包括协议机制的设计错误,发现协议死锁,或者不能正确工作,协议参数的调整等问题。 由于我们缓冲区判断满溢的条件存在问题,缓冲区溢出时网络层依然没有被关闭,导致运行程序时发现数据帧“丢失”;在协议参数的选择上也花了较长时间。 (5) 开发库方面遇到了哪些问题?包括库程序中的BUG,库函数文档不够清楚导致误解,库函数在所提供的功能结构上的缺憾导致编程效率低下。这些问题或建议影响不同模块之间功能界限的划分。 无法看到库函数的实现部分的代码,对各个参数的作用也没有详细清晰的说明,所以掌握这些函数花了较长时间,使用时也出现过很多错误。 (6) 总结本次实验,你在C 语言方面,协议软件方面,理论学习方面,软件工程方面等哪些方面上有所提高? 通过这次试验,我们对数据链路层的选择重传协议的机制有了很深刻的了解。很多书本上不是很懂的讲义,在我们进行试验的过程中,通过对模拟结果的分析与思考都一点点的理解了。而且这次试验是我们第一次模拟通信,让我们学会了windows下观察网络收发数据包模拟环境的搭建。 6.源程序清单 #include #define DATA 1 #define NAK 2 #define ACK 3 #define DATA_TIMER 3000 #define ACK_TIMER 1000 #define MAX_SEQ 63 #define NR_BUFS ((MAX_SEQ+1)/2) int no_nak=1; static int phl_ready = 0; struct FRAME { unsigned char kind; /*数据、确认、否定确认*/ unsigned char ack; unsigned char seq; unsigned char data[PKT_LEN]; unsigned int padding; };