中南大学计算机网络课程设计_计算机网络课程设计

2020-02-27 其他范文 下载本文

中南大学计算机网络课程设计由刀豆文库小编整理,希望给你工作、学习、生活带来方便,猜你可能喜欢“计算机网络课程设计”。

通信原理课程设计报告

专业班级

电子信息11xx

姓名学号

xxx(090911xxxx)

指导教师

陈科文、张金焕

设计时间

2014年7月

电子信息工程系 信息科学与工程学院

目录

第一章 课程设计要求和目的...........................................1 1.1 设计要求....................................................1 1.2 设计目的....................................................1 第二章 滑动窗口协议仿真.............................................1 2.1 设计要求....................................................1 2.2 设计思想....................................................1 2.3 编程实现过程................................................9 2.3.1 开发环境.............................................9 2.3.2 程序界面设计.........................................9 2.3.3 关键模块分析.........................................11 2.3.4 结果演示与分析.......................................18

第一章 课程设计要求和目的1.1设计要求

通过本课程教学,要求学生熟悉 TCP/IP 协议工作机制、熟悉基于 Socket 的网络通信程序的设计方法,熟练掌握至少一种编程语言及工具的使用。通过设计和调试有关程序,掌握一种网络协议或算法的编程实现方法或具体应用,同时设计一个相对独立的网络应用程序。

1.2 设计目的通过将理论与实践相结合,使学生进一步深入理解通信网的工作原理,掌握网络应用开发技术,学会应用所学理论知识来分析和解决实际问题,培养网络技术研究与开发的基本能力以及创新精神。

第二章 滑动窗口协议仿真

2.1设计要求

(1)程序按照滑动窗口协议实现端对端的数据传送。包括协议的各种策略,如包丢失、停等应答、超时等都应有所仿真实现。

(2)显示数据传送过程中的各项具体数据;双方帧的个数变化,帧序号,发送和接受速度,暂停或重传提示等。

(3)增加其它附加创新功能。程序应有图形化界面,显示直观、易操作。

2.2设计思想

滑动窗口机制

(1).窗口机制

滑动窗口协议的基本原理就是在任意时刻,发送方都维持了一个连续的允许发送的帧的序号,称为发送窗口;同时,接收方也维持了一个连续的允许接收的帧的序号,称为接收窗口。发送窗口和接收窗口的序号的上下界不一定要一样,甚至大小也可以不同。不同的滑动窗口协议窗口大小一般不同。发送方窗口内的序列号代表了那些已经被发送,但是还没有被确认的帧,或者是那些

可以被发送的帧。下面举一个例子(假设发送窗口尺寸为2,接收窗口尺寸为1):

图2-2-1

分析:①初始态,发送方没有帧发出,发送窗口前后沿相重合。接收方0号窗口打开,等待接收0号帧;②发送方打开0号窗口,表示已发出0帧但尚确认返回信息。此时接收窗口状态不变;③发送方打开0、1号窗口,表示0、1号帧均在等待确认之列。至此,发送方打开的窗口数已达规定限度,在未收到新的确认返回帧之前,发送方将暂停发送新的数据帧。接收窗口此时状态仍未变;④接收方已收到0号帧,0号窗口关闭,1号窗口打开,表示准备接收1号帧。此时发送窗口状态不变;⑤发送方收到接收方发来的0号帧确认返回信息,关闭0号窗口,表示从重发表中删除0号帧。此时接收窗口状态仍不变;⑥发送方继续发送2号帧,2号窗口打开,表示2号帧也纳入待确认之列。至此,发送方打开的窗口又已达规定限度,在未收到新的确认返回帧之前,发送方将暂停发送新的数据帧,此时接收窗口状态仍不变;⑦接收方已收到1号帧,1号窗口关闭,2号窗口打开,表示准备接收2号帧。此时发送窗口状态不变;⑧发送方收到接收方发来的1号帧收毕的确认信息,关闭1号窗口,表示从重发表中删除1号帧。此时接收窗口状态仍不变。

若从滑动窗口的观点来统一看待1比特滑动窗口、后退n及选择重传三种协议,它们的差别仅在于各自窗口尺寸的大小不同而已。1比特滑动窗口协议:发送窗口=1,接收窗口=1;后退n协议:发窗口>1,接收窗口>1;选择重传协议:发送窗口>1,接收窗口>1。(2).1比特滑动窗口协议

当发送窗口和接收窗口的大小固定为1时,滑动窗口协议退化为停等协议(stop-and-wait)。该协议规定发送方每发送一帧后就要停下来,等待接收方已正确接收的确认(acknowledgement)返回后才能继续发送下一帧。由于接收

方需要判断接收到的帧是新发的帧还是重新发送的帧,因此发送方要为每一个帧加一个序号。由于停等协议规定只有一帧完全发送成功后才能发送新的帧,因而只用一比特来编号就够了。其发送方和接收方运行的流程图如图所示。

图2-2-

2(3).后退n协议

由于停等协议要为每一个帧进行确认后才继续发送下一帧,大大降低了信道利用率,因此又提出了后退n协议。后退n协议中,发送方在发完一个数据帧后,不停下来等待应答帧,而是连续发送若干个数据帧,即使在连续发送过程中收到了接收方发来的应答帧,也可以继续发送。且发送方在每发送完一个数据帧时都要设置超时定时器。只要在所设置的超时时间内仍收到确认帧,就要重发相应的数据帧。如:当发送方发送了N个帧后,若发现该N帧的前一个帧在计时器超时后仍未返回其确认信息,则该帧被判为出错或丢失,此时发送方就不得不重新发送出错帧及其后的N帧。

图2-2-3

从这里不难看出,后退n协议一方面因连续发送数据帧而提高了效率,但另一方面,在重传时又必须把原来已正确传送过的数据帧进行重传(仅因这些数据帧之前有一个数据帧出了错),这种做法又使传送效率降低。由此可见,若传输信道的传输质量很差因而误码率较大时,连续测协议不一定优于停止等待协议。此协议中的发送窗口的大小为k,接收窗口仍是1。(4).选择重传协议

在后退n协议中,接收方若发现错误帧就不再接收后续的帧,即使是正确到达的帧,这显然是一种浪费。另一种效率更高的策略是当接收方发现某帧出错后,其后继续送来的正确的帧虽然不能立即递交给接收方的高层,但接收方仍可收下来,存放在一个缓冲区中,同时要求发送方重新传送出错的那一帧。一旦收到重新传来的帧后,就可以原已存于缓冲区中的其余帧一并按正确的顺序递交高层。这种方法称为选择重发(SELECTICE REPEAT),其工作过程如图所示。显然,选择重发减少了浪费,但要求接收方有足够大的缓冲区空间。滑动窗口协议

仍然考虑链路的延迟与带宽的乘积为8 K B,帧尺寸为1 K B的情形。让发送方在收到第一帧的A C K的同时准备发送第九帧。允许我们这样做的算法称为滑动窗口(sliding window),时间线如图2-2-3所示。1.滑动窗口算法

滑动窗口算法工作过程如下。首先,发送方为每1帧赋一个序号(sequence number),记作S e q N u m。现在,让我们忽略S e q N u m是由有限大小的头部字段实现的事实,而假设它能无限增大。发送方维护3个变量:发送窗口大

小(send window size),记作S W S,给出发送方能够发送但未确认的帧数的上界; L A R表示最近收到的确认帧(last acknowledgement re c e i v e d)的序号;L F S表示最近发送的帧(last frame sent)的序号,发送方还维持如下的不变式: LAR-LFR≤RWS

当一个确认到达时,发送方向右移动L A R,从而允许发送方发送另一帧。同时,发送方为所发的每个帧设置一个定时器,如果定时器在A C K到达之前超时,则重发此帧。注意:发送方必须存储最多S W S个帧,因为在它们得到确认之前必须准备重发。

接收方维护下面3个变量:接收窗口大小(receive window size),记为RW S,给出接收方所能接收的无序帧数目的上界; L A F表示可接收帧(l a rgestacceptable frame)的序号;L F R表示最近收到的帧(last frame re ce i v e d)的序号。接收方也维持如下不变式: LFS-LAR≤SWS

当一个具有顺序号S e q N u m的帧到达时,接收方采取如下行动:如果S e q N u m≤L F R或S e q N u m > L A F,那么帧不在接收窗口内,于是被丢弃;如果L F R<Se q N u m≤L A F,那么帧在接收窗口内,于是被接收。现在接收方需要决定是否发送一个A C K。设S e q N u m To A C K表示未被确认帧的最大序号,则序号小于或等于S e q N u m To Ac k的帧都已收到。即使已经收到更高序号的分组,接收方仍确认S e q N u m To A c k的接收。这种确认被称为是累积的(c u m u l a t i v e)。然后它设置L F R = S e q Nu m To A c k,并调整L A F = L F R + RW S。例如,假设L F R= 5(即,上次接收方发送的A C K是为了确认顺序号5的),并且RWS = 4。这意味着L A F = 9。如果帧7和8到达,则存储它们,因为它们在接收窗口内。然而并不需要发送A C K,因为帧6还没有到达。帧7和8被称为是错序到达的。(从技术上讲,接收方可以在帧7和8到达时重发帧5的A C K。)如果帧6当时到达了(或许它在第一次丢失后又重发从而晚到,或许它只是被延迟了),接收方确认帧8,L F R置为8,L A F置为1 2。如果实际上帧6丢失了,则出现发送方超时,重发帧6。我们看到,当发生超时时,传输数据量减少,这是因为发送方在帧6确认之前不能向前移动窗口。这意味着分组丢失时,此方案将不再保证管道满载。注意:分组丢失时间越长,这个问题越严重。注意,在这个例子中,接收方可以在帧7刚一到达时就为帧6发送一个认帧N A K(negative acknowledgment)。然而,由于发送方的超时机制足

以发现这种情况,发送N A K反而为发送方增加了复杂性,因此不必这样做。正如我们已提到的,当帧7和8到达时为帧5发送一个额外的A C K是合理的;在某些情况下,发送方可以使用重复的A C K作为一个帧丢失的线索。这两种方法都允许早期的分组丢失检测,有助于改进性能。关于这个方案的另一个变种是使用选择确认(selective acknowledgements)。即,接收方能够准确地确认那些已收到的帧,而不只是确认按顺序收到最高序号的帧。因此,在上例中,接收方能够确认帧7、8的接收。如果给发送方更多的信息,就能使其较容易地保持管道满载,但增加了实现的复杂性。

发送窗口大小是根据一段给定时间内链路上有多少待确认的帧来选择的;对于一个给定的延迟与带宽的乘积,S W S是容易计算的。另一方面,接收方可以将RW S设置为任何想要的值。通常的两种设置是:RW S= 1,表示接收方不存储任何错序到达的帧; RW S=S W S,表示接收方能够缓存发送方传输的任何帧。由于错序到达的帧的数目不可能超过S W S个,所以设置RWS >S W S没有意义。

2.有限顺序号和滑动窗口

现在我们再来讨论算法中做过的一个简化,即假设序号是可以无限增大的。当然,实际上是在一个有限的头部字段中说明一个帧的序号。例如,一个3比特字段意味着有8个可用序号0 ~ 7。因此序号必须可重用,或者说序号能回绕。这就带来了一个问题:要能够区别同一序号的不同次发送实例,这意味着可用序号的数目必须大于所允许的待确认帧的数目。例如,停止等待算法允许一次有1个待确认帧,并有2个不同的序号。假设序号空间中的序号数比待确认的帧数大1,即S W S ≤ M A a xS e q N u m-1,其中M a x Seq N u m 是可用序号数。这就够了吗?答案取决于RW S。如果RW S = 1,那么MaxSeqNum≥SWS+1是足够了。如果RW S等于S W S,那么有一个只比发送窗口尺寸大1的M a x S e q N u m是不够的。为看清这一点,考虑有8个序号0 ~ 7的情况,并且S W S = RW S = 7。假设发送方传输帧0 ~ 6,并且接收方成功接收,但A C K丢失。接收方现在希望接收帧7,0 ~ 5,但发送方超时,然后发送帧0 ~ 6。不幸的是,接收方期待的是第二次的帧0 ~ 5,得到的却是第一次的帧0 ~ 5。这正是我们想避免的情况。结果是,当RW S = S W S时,发送窗口的大小不能大于可用序号数的一半,或更准确地说,SWS

任意值的更一般的规则留做一个练习。还要注意,窗口的大小和序号空间之间的关系依赖于一个很明显以至于容易被忽略的假设,即帧在传输中不重新排序。这在直连的点到点链路上不能发生,因为在传输过程中一个帧不可能赶上另一个帧。

3.滑动窗口的实现

下面的例程说明我们如何实现滑动窗口算法的发送和接收的两个方面。该例程取自一个正在使用的协议,称为滑动窗口协议S W P(Sliding Window Pro t o c o l)。为了不涉及协议图中的邻近协议,我们用H L P(高层协议)表示S W P上层的协议,用L I N K(链路层协议)表示S W P下层的协议。我们先定义一对数据结构。首先,帧头部非常简单:它包含一个序号(S e q N u m)和一个确认号(A c k N u m)。它还包含一个标志(F l a g s)字段,表明帧是一个A C K帧还是携带数据的帧。

其次,滑动窗口算法的状态有如下结构。对于协议发送方,该状态包括如上所述的变量L A R和L F S,以及一个存放已发出但尚未确认的帧的队列(s e n d Q)。发送方状态还包含一个计数信号量(counting semaphore),称为s e n d Wi n d o w N o t F u l l。下面我们将会看到如何使用它,但一般来说,信号量是一个支持s e m Wa i t和s e m S i g n a l操作的同步原语。每次调用S e m S i g n al,信号量加1,每次调用S e m Wa i t,信号量减1。如果信号量减小,导致它的值小于0,那么调用进程阻塞(挂起)。一旦执行了足够的s e m S i g n a l操作而使信号量的值增大到大于0,在调用s e m Wa i t的过程中阻塞的进程就允许被恢复。对于协议的接收方,如前所述,该状态包含变量L F R,加上一个存放已收到的错序帧的队列(r e c v Q)。最后,虽然未显示,发送方和接收方的滑动窗口的大小分别由常量S W S和RW S表示。

S W P的发送方是由s e n d S W P过程实现的。这个例程很简单。首先,s e m Wa i t使这个进程在一个信号量上阻塞,直到它可以发另一帧。一旦允许继续,s e n d S W P设置帧头部中的顺序号,将此帧的拷贝存储在发送队列(s e n d Q)中,调度一个超时事件以便处理帧未被确认的情况,并将帧发给低层协议。

值得注意的一个细节是刚好在调用m s g A d d H dr之前调用s t o r e _ s w p _ h d r。该例程将存有S W P头部的C语言结构(s t a t e-> h d r)转化为能够安全放在消息前面的字节串(h b u f)。该例程(未给出)必须将头部中的每一个整数字段转化为网络字节顺序,并且去掉编译程序加入C语言结构中的任意填充。7.1节将详细讨论字节顺序的问题,但现在,假设该例程将多字整数中最高有效位放在最高地址字节就足够了。这个例程的另一个复杂性是使用s e m Wa i t 和s e n dW i n d ow N o t F u l l 信号量。S e n dWi n d o w N o t F u l l被初始化为发送方滑动窗口的大小S W S(未给出这一初始化)。发送方每传输一帧,s e m Wa i t操作将这个数减1,如果减小到0,则阻塞发送方进程。每收到一个A C K,在d e l i v e r SW P中调用s e m S i g n a l操作(见下面)将此数加1,从而激活正在等待的发送方进程。

在继续介绍S W P的接收方之前,需要调整一个看上去不一致的地方。一方面,我们说过,高层协议通过调用s e n d操作来请求低层协议的服务,所以我们就希望通过S W P发送消息的协议能够调用s e n d(S W P, p a c k e t)。另一方面,用来实现S W P的发送操作的过程叫做s e n d S W P,并且它的第一个参数是一个状态变量(S w p S t a t e)。结果怎样呢?答案是,操作系统提供了粘结代码将对s e n d的一般调用转化为对s e n d S W P的特定协议调用的粘结代码。这个粘结代码将s e n d的第一个参数(协议变量S W P)映射为一个指向s e n d S W P的函数指针和一个指向S W P工作时所需的协议状态的指针。我们之所以通过一般函数调用使高层协议间接调用特定协议函数,是因为我们想限制高层协议中对低层协议编码的信息量。这使得将来能够比较容易地改变协议图的配置。现在来看d e l i v e r操作的S W P的特定协议实现,它在过程d e l i v e r SW P中实现。这个例程实际上处理两种不同类型的输入消息:本结点已发出帧的A C K和到达这个结点的数据帧。在某种意义上,这个例程的ACK部分是与send SWP中所给算法的发送方相对应的。通过检验头部的F l a g s字段可以确定输入的消息是ACK还是一个数据帧。注意,这种特殊的实现不支持数据帧中捎带A C K。当输入帧是一个ACK时,delive rSWP仅仅在发送队列(send Q)中找到与此ACK相应的位置(slot),取消超时事件,并且释放保存在那一位置的帧。由于A C K可能是累积的,所以这项工作实际上是在一个循环中进行的。对于这种情况值得注意的另一个问题是子例程swp In Wind o w的调用。这个子例程在下面给出,它确保被确认帧的序号是在发送方当前希望收到的A C K的范围之内。当输入帧包含数据时,d e l i v e r S W P首先调用m s g S t r i pH d r和l o a d _ s w p _ h d r以便从帧中提取头部。例程l o a d _ s w p_ h d r对应着前面讨论的s t o r e _ s w p _ h d r,它将一个字节串转化为容纳S W P头部的C语言数据结构。然后d e l i v e r SW P调用s w p I n Wi n d o w以确保帧序号在期望的序号范围内。如果是这样,例程在已收到的连续的帧的集合上循环,并通过调用d e l i v e r HL P例程将它们传给上层协议。它也要向发送方发送累积的A C K,但却是通过在接收队列上循环来实现的(它没有使用本节前面给出的s e q N u m To Ac k变量)。

最后,s w p I n Window是一个简单的子例程,它检查一个给定的序号是否落在某个最大和最小顺序号之间。4.帧顺序和流量控制

滑动窗口协议可能是计算机网络中最著名的算法。然而,关于该算法易产生混淆的是,它可以有三个不同的功能,第一个功能是本节的重点,即在不可靠链路上可靠地传输帧。(一般来说,该算法被用于在一个不可靠的网络上可靠地传输消息。)这是该算法的核心功能。

滑动窗口算法的第二个功能是用于保持帧的传输顺序。这在接收方比较容易实现,因为每个帧有一个序号,接收方要保证已经向上层协议传递了所有序号比当前帧小的帧,才向上传送该当前帧。即,接收方缓存了(即没有传送)错序的帧。本节描述的滑动窗口算法确实保持了帧的顺序,尽管我们可以想象一个变异,即接收方没有等待更早传送的帧都到达就将帧传给下一个协议。我们可以提出的一个问题是:我们是否确实需要滑动窗口协议来保持帧的顺序,或者,这样的功能在链路层是否是不必要的。不幸的是,我们还没有看到足够多的网络体系结构来回答这个问题我们首先需要理解的是,点到点链路序列如何由交换机连接而形成一条端到端的路径。滑动窗口算法的第三个功能是,它有时支持流量控制(f l o w c o n t ro l),它是一种接收方能够控制发送方使其降低速度的反馈机制。这种机制用于抑制发送方发送速度过快,即抑制传输比接收方所能处理的更多的数据。这通常通过扩展滑动窗口协议完成,使接收方不仅确认收到的帧,而且通知发送方它还可接收多少帧。可接收的帧数对应着接收方空闲的缓冲区数。在按序传递的情况下,在将流量控制并入滑动窗口协议之前,我们应该确信流量控制在链路层是必要的。

2.3编程实现过程 2.3.1 开发环境 操作系统:Windows 7旗舰版

开发语言:C++ / MFC 编译环境:MS Visual C++6.0 2.3.2 程序界面设计

此程序由于功能需要,分别设计了发送端(图2-3-2-1)和接收端(图2-3-2-2)两个MFC界面,实例如下:

图2-3-2-1

图2-3-1-2

2.3.3 关键模块分析

1.窗口初始化

BOOL CSenderDlg::OnInitDialog(){

// Set the icon for this dialog.The framework does this automatically // when the application's main window is not a dialog SetIcon(m_hIcon, TRUE);SetIcon(m_hIcon, FALSE);

// Set big icon CMenu* pSysMenu = GetSystemMenu(FALSE);if(pSysMenu!= NULL){

} CString strAboutMenu;strAboutMenu.LoadString(IDS_ABOUTBOX);if(!strAboutMenu.IsEmpty()){

} pSysMenu->AppendMenu(MF_SEPARATOR);pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);// IDM_ABOUTBOX must be in the system command range.ASSERT((IDM_ABOUTBOX & 0xFFF0)== IDM_ABOUTBOX);ASSERT(IDM_ABOUTBOX

// Set small icon

// TODO: Add extra initialization here //初始化WinSock WSADATA wsa;if(WSAStartup(MAKEWORD(2, 2), &wsa)!= 0){

} AfxMeageBox(“Failed to initialize the winsock 2 stack”);return FALSE;//创建UDP Sender Socket if((m_UDPSndrSocket = WSASocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP, NULL, 0, WSA_FLAG_OVERLAPPED))== INVALID_SOCKET)

//绑定Sender UDP端口

if(bind(m_UDPSndrSocket,(sockaddr*)&UDPSndrAddr, sizeof(UDPSndrAddr))== //填充本地UDP Sender Socket地址结构 SOCKADDR_IN UDPSndrAddr;memset(&UDPSndrAddr, 0, sizeof(SOCKADDR_IN));UDPSndrAddr.sin_family = AF_INET;UDPSndrAddr.sin_port = htons(3073);UDPSndrAddr.sin_addr.S_un.S_addr = inet_addr(“127.0.0.1”);{

} AfxMeageBox(“Failed to create UDPSocket”);return FALSE;SOCKET_ERROR)

{ AfxMeageBox(“Failed to bind UDPSndrAddr”);return FALSE;

} } //填充Receiver UDP地址

memset(&m_UDPRcvrAddr, 0, sizeof(SOCKADDR_IN));m_UDPRcvrAddr.sin_family = AF_INET;m_UDPRcvrAddr.sin_port = htons(3074);m_UDPRcvrAddr.sin_addr.S_un.S_addr = inet_addr(“127.0.0.1”);//创建UDP数据包接收线程 DWORD dwThreadId;CreateThread(NULL, 0, UdpReceiveThread, this, 0, &dwThreadId);return TRUE;// return TRUE unle you set the focus to a control void CSenderDlg::OnSysCommand(UINT nID, LPARAM lParam){

} if((nID & 0xFFF0)== IDM_ABOUTBOX){

} else { } CDialog::OnSysCommand(nID, lParam);CAboutDlg dlgAbout;dlgAbout.DoModal();

2.数据发送

void CSenderDlg::OnStartSend()

{

// TODO: Add your control notification handler code here //获取对话框数据 if(!UpdateData(TRUE))return;//初始化所有参数 if(m_pOutBuf!= NULL)delete []m_pOutBuf;m_pOutBuf = new frame[m_SendWndSize];m_iBuffered = 0;

//当前滑动窗口大小

//发送窗口左侧 m_ackExpected = 0;

m_nextFrameToSend = 0;//发送窗口右侧+1 for(int i=0;i

= “ ”;int iSeq;if(!m_strFrameLost.IsEmpty()){

strcpy(tmp, m_strFrameLost);token = strtok(tmp, seps);while(token!= NULL){

iSeq = atoi(token);token = strtok(NULL, seps);if(iSeq MAX_SEQ)

} {

} m_errArray[iSeq] = LOST_ERR;AfxMeageBox(“Invalid seqno in LostFrame box, ignore it”);continue;} if(!m_strChksumErr.IsEmpty()){

strcpy(tmp, m_strChksumErr);token = strtok(tmp, seps);while(token!= NULL){

} iSeq = atoi(token);token = strtok(NULL, seps);if(iSeq MAX_SEQ){

} m_errArray[iSeq] = CKSUM_ERR;AfxMeageBox(“Invalid seqno in ChksumErr box, ignore it”);continue;} //启动网络层数据发送定时器

SetTimer(ID_SEND_TIMER, m_SendInterval, NULL);//窗口界面控制

GetDlgItem(IDC_SEND_WND_SIZE)->EnableWindow(FALSE);

} GetDlgItem(IDC_SEND_INTERVAL)->EnableWindow(FALSE);GetDlgItem(IDC_RESEND_TIMER)->EnableWindow(FALSE);GetDlgItem(IDC_RANDOM_ERR)->EnableWindow(FALSE);GetDlgItem(IDC_MANUAL_ERR)->EnableWindow(FALSE);GetDlgItem(IDC_CHKSUM_ERR)->EnableWindow(FALSE);GetDlgItem(IDC_FRAME_LOST)->EnableWindow(FALSE);GetDlgItem(IDC_START_SEND)->EnableWindow(FALSE);GetDlgItem(IDC_STOP_SEND)->EnableWindow();CString strMsg;strMsg.Format(“%d”, m_ackExpected);GetDlgItem(IDC_BOTTOM)->SetWindowText(strMsg);strMsg.Format(“%d”, m_nextFrameToSend);GetDlgItem(IDC_TOP)->SetWindowText(strMsg);GetDlgItem(IDC_CUR_FRAME)->SetWindowText(“0”);

3.数据接收

void CReceiverDlg::OnStartRecv(){

// TODO: Add your control notification handler code here //获取对话框数据 if(!UpdateData(TRUE))return;//初始化所有参数 if(m_pInBuf!= NULL)delete []m_pInBuf;m_pInBuf = new frame[m_RecvWndSize];if(m_pArrived!= NULL)delete []m_pArrived;

m_pArrived = new BOOL[m_RecvWndSize];for(int i=0;i

//接收窗口左侧 m_frameExpected = 0;m_tooFar = m_RecvWndSize;//接收窗口右侧+1 for(i=0;i

= “ ”;int iSeq;if(!m_strAckLost.IsEmpty()){

strcpy(tmp, m_strAckLost);token = strtok(tmp, seps);while(token!= NULL){

iSeq = atoi(token);token = strtok(NULL, seps);if(iSeq MAX_SEQ){

} m_errArray[iSeq] = LOST_ERR;

AfxMeageBox(“Invalid seqno in LostFrame box, ignore it”);continue;

} } } //启动网络层数据接收定时器,模拟接收速率限制 SetTimer(ID_RECV_TIMER, m_RecvInterval, NULL);//窗口界面控制

GetDlgItem(IDC_RECV_WND_SIZE)->EnableWindow(FALSE);GetDlgItem(IDC_RECV_INTERVAL)->EnableWindow(FALSE);GetDlgItem(IDC_AUX_TIMER)->EnableWindow(FALSE);GetDlgItem(IDC_RANDOM_ERR)->EnableWindow(FALSE);GetDlgItem(IDC_MANUAL_ERR)->EnableWindow(FALSE);GetDlgItem(IDC_EDIT_ERR_ACK)->EnableWindow(FALSE);GetDlgItem(IDC_EDIT_LOST_ACK)->EnableWindow(FALSE);GetDlgItem(ID_START_RECV)->EnableWindow(FALSE);GetDlgItem(IDC_STOP_RECV)->EnableWindow();CString strMsg;strMsg.Format(“%d”, m_iTokenCount);GetDlgItem(IDC_CUR_TOKEN)->SetWindowText(strMsg);strMsg.Format(“%d”, m_frameExpected);GetDlgItem(IDC_BOTTOM)->SetWindowText(strMsg);strMsg.Format(“%d”, m_tooFar);GetDlgItem(IDC_TOP)->SetWindowText(strMsg);GetDlgItem(IDC_CUR_RCVD)->SetWindowText(“0”);

2.3.4 结果演示与分析

1.正常发送模式测试

图2-3-4-1正常发送模式测试——发送端

图2-3-4-2正常发送模式测试——接收端

发送窗口与接收窗口都是8,序列号为从0到15,发送了8帧以后发送方收到ack7,表示接收方对发送方前8帧的确认。注意:尽管接收方辅助定时器设置为2秒,但接收方对0号帧的确认并没有在收到0帧2秒后发出,这是因为在辅助定时器超时之前,后续到来的正确的帧会重置(reset)辅助定时器,使其被重新设为2秒,因此,直到7号帧到达后,发送方窗口被占满而停止发送,此时接收方辅助定时器开始计时,并在2秒后发送ack7,表示对7号帧之前所有帧的确认。与此同时,在发送方收到ack7确认帧时,已经经过的时间为9秒,而重发定时器设置为10秒,因此并没有导致0号帧超时重传。可见,辅助定时器与超时定时器的设置是密切相关的,要想滑动窗口协议正确流畅的运行,将相关参数调整到一个合适的值很十分必要的。一个简单的规则是,与数据帧相关联的重发定时器的超时间隔应显著大于辅助定时器的超时间隔(事实上,重发定时器的值至少应大于等于辅助定时器超时间隔与发送窗口最大值之和)。

1)帧校验错测试

在做新的测试前,首先将发送端和接收端进行重置,即两端都先停止再重新开始,然后再做后续测试(如果需要,停止后可以修改相关参数)。

图2-3-4-3帧校验错测试——发送端

图2-3-4-4帧校验错测试——接收端

通过手工设置2号帧的校验和错误来模拟信道传输中的误码情况。可以看到接收方在收到2号错误帧后马上向发送方回送了一个nak2的否定应答帧,发送方在收到nak2后也立即重传了该帧,因此nak机制加速了错误帧的重传过程(否则如果接收方直接丢弃的话,就只能等到发送方2号帧的重发定时器超时后进行重传)

2)帧丢失测试

图2-3-4-5帧丢失测试——发送端

图2-3-4-6帧丢失测试——接收端

同帧校验和错误类似,帧丢失错误同样会引发接收端回送nak否定应答消息。不同的是,nak否定应答帧是在丢失帧的下一帧收到后发出的。如图5所示,由于传输过程中2号帧丢失,接收端在收到1号帧后,接下来收到了3号帧,这时,接收端知道由于某种原因2号帧丢失了,于是立即发送了2号帧的否定应答帧。在发送端收到该nak2帧后,也马上重传了该帧,nak机制同样加快了对丢失帧的重传操作。

3)确认帧丢失测试

图2-3-4-7确认帧丢失测试——发送端

图2-3-4-8确认帧丢失测试——接收端

注意,本次测试前首先调整了接收端的辅助定时器时间参数,将回送应答的时间设置为0.5秒,这样接收方每收到一帧,都会在下一帧到来之前回送上一帧的确认。如果不这样做,仍像正常测试时使用的参数那样,就不会对2号帧回送应答消息,原因在进行正常情况测试时已经讲过,因为3号帧的正确到达重置了辅助定时器,因此只有到7号帧发出后发送方因窗口满而停止,接收端辅助定时器超时,回送ack7,一次确认了7号帧之前所有的帧,这样就看不到2号应答帧丢失的效果了。

调整参数之后进行应答帧丢失测试,可以看到接收端发送2号应答帧时丢失了。发送端虽然没有收到2号帧的应答消息,但因发送窗口不满,而且也没有任何重传定时器到时,所以发送方继续发送后续的3号帧,接收端在收到3号帧后回送ack3,这次应答帧没有丢失。这样当发送端收到3号帧的应答帧时,它就知道3号帧之前的所有帧都已被正确的接收了,因此2号帧也被确认,发送窗口向后移动,再往后的传输过程就正常一应一答的进行。

4)流量控制测试

图2-3-4-9流量控制测试——接收端

图2-3-4-10流量控制测试——接收端

滑动窗口协议还有流量控制功能,即它可以保证缓慢的接收端不会被快速的发送端发来的大量数据所淹没。如图7所示,首先调整发送定时器为500ms,即每秒发送2个数据包,接收端参数是:接收窗口大小为4,接收速率为每秒处理1个包。从图中可以看到,7号帧之前的帧还可以正常收发(这是由于令牌桶算法在短时间内有一定的处理突发流量的能力),从7号帧开始出现丢包现象(此时令牌数为0,令牌桶算法会在长时间内保证将流量限制在某一平均速率)。由于接收端处理能力不足,在丢包后无法及时向发送端回送确认,从而导致发送端窗口被占满而不能继续发送,在发送窗口内没有及时确认的帧都会被重发,这样就控制了两端收发过程的同步,使发送窗口的移动速度与接收窗口保持一致。

从接收端日志中含有accepted的记录中可以看出,尽管在发送端速度快的情况下,接收端还是可以依次按序的将数据包提交给网络层,从而也说明协议的运行是正确的。

《中南大学计算机网络课程设计.docx》
将本文的Word文档下载,方便收藏和打印
推荐度:
中南大学计算机网络课程设计
点击下载文档
相关专题 计算机网络课程设计 计算机网络 中南大学 课程设计 计算机网络课程设计 计算机网络 中南大学 课程设计
[其他范文]相关推荐
    [其他范文]热门文章
      下载全文