参考一:
TCP提供流量控制。TCP总是告诉对端它能够接收多少字节的数据(通告窗口),该窗口在任何时刻都指出接收缓冲区中可用空间,从而确保发送端发送的数据不会溢出接收缓冲区。
如图所示,tcp发送主和接收方既有发送缓冲区,又有接收缓冲区,流量控制的滑动窗口通过探测接收端的可用缓冲区实现,而用于拥塞管理的拥塞窗口是通过限制发送端的发送速率实现的。图中向上箭头表示接收缓冲区,向下箭头表示发送缓冲区。
相关变量说明:
LastByteRead为接收端从接收缓冲区读取的最后一个字节报文编号;
LastByteRcv为从发送端经接收端IP层发给接收缓冲区的最后一个字节编号;
LastByteSent为发送端最新发出的一个字节编号;
LastByteAck为发送端已被确认的发送出去的数据字节编号;
我们考虑接收端的缓冲区变化,当应用程序读取数据时,可用空间会变大,当收到 ip层分发的数据时,可用空间会变小,事实上,可以给出以下计算公式:
Advertise_Window=BUFFER-(LastByteRcv-LastByteRead);
其中LastByteRcv-LastByteRead为待读取的数据字节数,而BUFFER大小是固定的,那么可用的空间就是Advertise_Window,这就是接收端需要向发送端通告的大小变化的滑动窗口。
那么发送端发送的数据量应该在接收端能够承受的范围内,那么接收端还有多少数据在重发队列里面准备发送呢?就是LastByteSent-LastByteAck,因此有以下计算公式:
LastByteSent-LastByteAck<=Advertise_Window;
这就是滑动窗口的实现机制,为了让左边的数值变小,就要考虑减小LastByteSent,即减少新数据的发送,或者增大LastByteAck,等待更多发出去的报文被确认;当然,考虑到网络利用率,发送报文数据在滑动窗口限制范围内即可。
实际上,发送方发送数据速率还有拥塞窗口的限制,此处一并给出公式:
LastByteSent-LastByteAck<=MIN(Advertise_window,Cong_Window)
最后再给出通常意义的滑动窗口示意图:
假定待接收的数据(LastByteRcv-LastByteRead)是一个双向的栈,则此栈空间越小则接收端能够接收到的数据就越多。
当有新的数据从下层分发过来时,就相当于左侧入栈,栈占用空间变大;
当有数据被应用层读取时,就相当于右侧出栈,栈占用空间变小;
最后说明:通知窗口是在TCP选项中协商的。
参考二:
参考三:
1、流量控制是管理两端的流量,以免会产生发送过块导致收端溢出,或者因收端处理太快而浪费时间的状态。用的是:滑动窗口,以字节为单位
2、窗口有3种动作:展开(右边向右),合拢(左边向右),收缩(右边向左)这三种动作受接收端的控制。
合拢:表示已经收到相应字节的确认了
展开:表示允许缓存发送更多的字节
收缩(非常不希望出现的,某些实现是禁止的):表示本来可以发送的,现在不能发送;但是如果收缩的是那些已经发出的,就会有问题;为了避免,收端会等待到缓存中有更多缓存空间时才进行通信。
发端窗口的大小取决于收端的窗口大小rwnd(TCP报文的窗口大小字段)和拥塞窗口大小cwnd(见拥塞控制)
发端窗口大小 = min{ rwnd , cwnd };
3、关闭窗口:窗口缩回有个例外,就是发送rwnd=0表示暂时不愿意接收数据。这种情况下,发端不是把窗口收缩,二是停止发送数据。(为了比避免死锁,会用一些探测报定时发送试探,见定时器一节)
4、问题:某些时候,由于发端或收端的数据很慢,会引起大量的1字节数据痛惜,浪费很多资源。
(1)、发端的进程产生数据很慢时候,时不时的来个1字节数据,那么TCP就会1字节1字节的发送,效率很低。
解决方法(Nagle算法):
a、将第一块数据发出去
b、然后等到发送缓存有足够多的数据(最大报文段长度),或者等到收端确认的ACK时再发送数据。
c、重复b的过程
(2)、收端进程由于消耗数据很慢,所以可能会有这么一种情况,收端会发送其窗口大小为1的信息,然后有是1字节的传输
解决办法(2种)
a、Clark方法:在接收缓存的一半变空,或者有足够空间放最大报文长度之前,宣告接收窗口大小为0
b、推迟确认:在对收到的报文段确认之前等待到足够的接收缓存,或者等待到一个时间段(现在一般定义500ms)
(1).窗口机制
滑动窗口协议的基本原理就是在任意时刻,发送方都维持了一个连续的允许发送的帧的序号,称为发送窗口;同时,接收方也维持了一个连续的允许接收的帧的序号,称为接收窗口。发送窗口和接收窗口的序号的上下界不一定要一样,甚至大小也可以不同。不同的滑动窗口协议窗口大小一般不同。发送方窗口内的序列号代表了那些已经被发送,但是还没有被确认的帧,或者是那些可以被发送的帧。下面举一个例子(假设发送窗口尺寸为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)返回后才能继续发送下一帧。由于接收方需要判断接收到的帧是新发的帧还是重新发送的帧,因此发送方要为每一个帧加一个序号。由于停等协议规定只有一帧完全发送成功后才能发送新的帧,因而只用一比特来编号就够了。其发送方和接收方运行的流程图如图所示。
(3).后退n协议
由于停等协议要为每一个帧进行确认后才继续发送下一帧,大大降低了信道利用率,因此又提出了后退n协议。后退n协议中,发送方在发完一个数据帧后,不停下来等待应答帧,而是连续发送若干个数据帧,即使在连续发送过程中收到了接收方发来的应答帧,也可以继续发送。且发送方在每发送完一个数据帧时都要设置超时定时器。只要在所设置的超时时间内仍收到确认帧,就要重发相应的数据帧。如:当发送方发送了N个帧后,若发现该N帧的前一个帧在计时器超时后仍未返回其确认信息,则该帧被判为出错或丢失,此时发送方就不得不重新发送出错帧及其后的N帧。
从这里不难看出,后退n协议一方面因连续发送数据帧而提高了效率,但另一方面,在重传时又必须把原来已正确传送过的数据帧进行重传(仅因这些数据帧之前有一个数据帧出了错),这种做法又使传送效率降低。由此可见,若传输信道的传输质量很差因而误码率较大时,连续测协议不一定优于停止等待协议。此协议中的发送窗口的大小为k,接收窗口仍是1。
(4).选择重传协议
在后退n协议中,接收方若发现错误帧就不再接收后续的帧,即使是正确到达的帧,这显然是一种浪费。另一种效率更高的策略是当接收方发现某帧出错后,其后继续送来的正确的帧虽然不能立即递交给接收方的高层,但接收方仍可收下来,存放在一个缓冲区中,同时要求发送方重新传送出错的那一帧。一旦收到重新传来的帧后,就可以原已存于缓冲区中的其余帧一并按正确的顺序递交高层。这种方法称为选择重发(SELECTICE REPEAT),其工作过程如图所示。显然,选择重发减少了浪费,但要求接收方有足够大的缓冲区空间。
滑动窗口协议可以用图四来形象表示。
图中我们已经将字节进行了1到11的编号。由接收者通告的窗口称为提议窗口(offered window),它覆盖了第4到第9个字节,意味着接收方已经确认了第3字节之前(包括第3字节)的数据,并且通告窗口的大小是6。窗口大小与确认的顺序号(acknowledged sequence number)有关。发送者计算它的可用窗口(usable window),用以度量它可以立即发送多少数据。
随着接收者对收到数据的确认,滑动窗口随时向右移动。窗口两端的相关运动增加或减少着窗口大小。我们使用3个术语来描述窗口边缘(edge)的左右运动。
1. 当窗口左边缘靠近右边缘时称窗口闭合(window closes)。窗口闭合发生在数据已经发送并被确认的情况下。
2. 当窗口右边缘向右移动时称窗口打开(window opens)。窗口打开发生在另一端的接收进程读取已确认数据的时候,它释放了TCP接收缓冲区的空间。
3. 当窗口右边缘向左移动时称窗口收缩(window shrinks)。Host Requirement RFC强烈不鼓励这种做法,但TCP必须能够在一端发生这种情况时进行处理。
图五表示了这三个术语。由于窗口的左边缘是受从连接另一端收到的确认号来控制的,因此它不会向左移动。如果收到一个ACK要求将左边缘向左移动,那么它是一个重复的(duplicate)的确认,并被丢弃。
如果窗口左边缘重合了右边缘,就称它为零窗口(zero window)。它将停止发送者传输任何数据。
示例
图六显示了图一数据传输中TCP滑动窗口的动态变化
以此图为例,我们可以总结几个要点:
1. 发送者不必传送满窗口大小的数据。
2. 收到接收者对数据的确认后,窗口向右滑动。这是由于窗口大小与确认顺序号相关。
3. 从段7到段8的变化,可以看出窗口可以减小,但窗口右边缘不能向左移动。
4. 接收者不必等待窗口被填满才发送确认。在许多实现中,接收者每收到两个段发送一个确认。