zoukankan      html  css  js  c++  java
  • TCP协议的流量控制和拥塞控制

    一开始,我总是容易把这2个概念搞混淆了,因此,为了加深理解,我写出来整理下思路。

    一:流量控制

    什么是流量控制,它涉及到哪些内容呢?

    首先,我们看看一个最简单的tcp传输涉及到哪些东西

    发送端,数据,网络,接收端(对端)

    最基本的就是这4个对象。

    流量控制是什么: 流量是什么?肯定就是数据。因为数据流动就形成了流量。
    控制呢,控制谁?谁被控制?这就涉及到发送端和接收端了。这2端来进行“控制”和“被控制”。

    正常情况下,发送端发送数据,接收端接收数据。就这么一个过程。2端也相安无事。

    突然,发生了不正常情况,发送端发送数据加快了,接收端按照原先的情况接收数据就接收不过来,接收端缓冲区满了,不能在装多余的数据了,那多余的数据就会被丢弃,这样会导致发送端触发重发机制重发数据。所以必须进行控制。

    流量控制就是:

    如果发送端发送的数据过快,接收端来不及接收,那么分组数据就会丢失。为了避免这种数据丢失,就需要控制发送者的速度,使得接收者来得及接收,这就是流量控制。

    为了控制发送者的速度,我们要怎么做呢?

    TCP最开始是以1个段为单位进行数据发送,每发送一个段就进行一次确认应答处理。想想看,这样的传输方式有什么缺点呢,是不是传输的量少,传输效率就下降,且确认应答也会增多。

    既然传输1个段有这些问题,那我一次能不能多传几个段呢?当然是可以的,这就引入了窗口的概念。多个段组成一个窗口进行连续发送。

    前面我们讲数据超时重发时,说过序列号,就是对传送的数据按顺序进行编号。窗口就用到了这个序列号,利用序列号来进行分段编号。然后把分段组织起来变成一个窗口。

    把数据分段编号,比如:

    1. 1-1000 为第一段
    2. 1001-2000 为第二段
    3. 2001-3000 为第三段
    4. 3001-4000 为第四段
    5. 4001-5000 为第五段

    把数据进行了分段,这时候发送端发送一个段以后不必要一直等待确认应答,而是可以继续发送数据。而接收端确认时,不必每次确认,而是可以以更大的单位进行确认。

    但是发送端也不能一直发送不进行确认,这样发送端不知道接收端是啥子情况。所以整理我们必须也控制一下,比如说我发送4个分段,就需要进行确认才发送新的数据。这4个分段就组成了一个窗口大小

    窗口大小:

    就是指无需等待确认应答就可以继续发送数据的最大值

    这个机制使用了大量缓冲区,通过对多个段同时确认应答。

    接收端的窗口大小,发送端是怎么知道的?

    1、建立连接时

    接收端发送ACK确认时会告诉发送端,我接收端的窗口大小是多少。tcp里用rwnd表示(receiver window,接收端窗口)

    2、建立连接后发送数据

    接收方每次收到数据包后在发送确认报文时,同时告诉发送方自己的缓存区还剩余多少是空闲,我们也把缓存区的剩余大小称之为接收窗口大小,用变量win来表示接收窗口的大小。

    发送方收到之后,便会调整自己的发送速率,也就是调整自己发送窗口的大小,当发送方收到接收窗口的大小为0时,发送方就会停止发送数据,防止出现大量丢包情况的发生。

    在TCP的首部中,有一个16位窗口字段,此字段就是用来存放窗口大小信息的
    

    假如我们有如下分段数组需要发送:

    1. 1-1000 为第一段
    2. 1001-2000 为第二段
    3. 2001-3000 为第三段
    4. 3001-4000 为第四段
    5. 4001-5000 为第五段
    6. ... ...

    |1-1000|1001-2000|2001-3000|3001-4000|4001-5000|50001-6000|6001-7000|70001-8000|... ...|

    比如1001-5000 组成一个窗口(四个分段)进行数据发送,在这个窗口内的数据即使没有收到确认应答也可以发送出去。如果从该窗口发送的数据在传输中丢失,也需要进行重发。因此,发送端主机在等待应答号返回前,也必须在缓冲区中保留这部分数据。

    在收到确认应答的情况下,可以将窗口位置滑动到确认应答号的位置。这样可以顺序的将多个分段同时发送以提高通信的效率和性能。这种机制就叫滑动窗口机制。当然这个窗口大小也是会根据接收端返回的应答窗口大小进行调整。这个就是流控制(流量控制)。

    每次接收端返回一个确认号,比如2001,3001,4001,收到3个确认号,没有收到5001,那么接收端会重复发3次4001,发送端主机连续3次收到同一个确认应答,就会对其进行重发。这个机制比超时管理更有效,因此也称为快速重发控制

    二:拥塞控制

    还是让我们首先来看看,一个最简单的tcp传输涉及到哪些东西

    发送端,数据,网络,接收端(对端)

    流量控制是针对发送端的,是接收端指示发送端使用多大的发送窗口。拥塞控制是针对网络的。他俩是不同的。

    网络发生拥塞了,当然整个网络的传输速率就会下降了。其实网络里包含路由器,交换机,主机等多种网络设备。

    当主机发送到网络的数据包数量超过了网络的承载能力时,就会发生拥塞。如果在继续大量发送,就可能造成网络崩溃。

    方法一:

    TCP的拥塞控制策略:
    TCP处理拥塞策略一般基于3个阶段:慢开始、拥塞避免 和 拥塞检测

    慢开始:指数增大

    慢开始:发送端从非常慢的传输速率开始,但是很快就把速率增大到一个阙值。当到达阙值门限后,数据的增长开始放慢。最后,只要一检测到拥塞,发送端就回到慢开始或者拥塞避免阶段。

    慢开始:指数增大

    慢开始算法的思想:即拥塞窗口cwnd从1个最大报文段的长度(MSS)开始。MSS的数值是在连接建立时来确定的。每当一个报文被确认,拥塞窗口就增大1个MSS。随后是2,4,8...,按指数规律增大。

    以下说明这个指数增长的规律:

    发送方从cwnd=1 MSS 开始。在第一个ACK到达后,拥塞窗口增加1,也就是说现在cwnd=2。此时发送2个报文段。当相应2个ACK到达后,对于每一个ACK,窗口大小增加1 MSS,这就表示现在cwnd=4。此时发送4个报文段。当4个ACK到达后,窗口大小又增加4,也就是cwnd=8。 依次类推...

    但是慢开始也不能无限的增长下去。慢开始无限增大,cwnd也会变得很大,这样必然会造成网络拥塞,所以要有一个停止阶段。发送方有一个称为ssthresh(慢开始门限)的变量。 当以字节计算的窗口大小达到这个ssthresh值时,慢开始阶段结束,++并进入下一个阶段++ - 拥塞避免

    拥塞避免:加法增大

    拥塞避免:加法增大

    我们从慢开始算法开始,拥塞窗口大小按照指数规律增长。但是为了发生拥塞之前避免它,就必须使指数增长变慢。于是TCP又定义了另外一个算法,叫做拥塞避免(congestion avoidance),使cwnd的值按照加法规律增长,而不是按照指数规律增长。

    当拥塞窗口的大小达到慢开始的门限时(ssthresh),慢开始阶段就停止了,这时,加法增加阶段就开始了。

    加法增的算法思想:
    每当一个整个窗口中的报文段被确认后,拥塞窗口大小才增加1。 一个窗口就是指在一个RTT期间传输的报文段的数量。换言之,这个增长是基于RTT的,而不是基于到达的ACK的数量。

    加法增的算法规律:

    • 1.开始时: cwnd = i
    • 2.经过1 RTT后: cwnd = i + 1
    • 3.经过2 RTT后: cwnd = i + 2
    • 4.经过3 RTT后: cwnd = i + 3

    在拥塞避免算法中,拥塞窗口的大小按照加法规律增长,直到检测到拥塞为止

    拥塞检测:乘法减小

    那怎么才能检测到拥塞现象呢?
    做法就是:让发送方重传一个报文段。

    这是TCP做出的一个重要的假设,之所以要重传报文是为了恢复一个遗失的分组,而这个分组假设是因为某个路由器有太多的输入分组而不得不丢弃,也就是说,路由器或者网络已变得超载和拥塞了。

    重传可以发生以下2中情况:

    • 1.当RTO计时器超时
    • 2.当收到了三个重复的ACK应答时

    反正不管哪一种情况,门限值都要下降到一半(乘法减小)

    整个拥塞流程梳理下

    1)拥塞窗口cwnd初始化为1个报文段,慢开始门限初始值为16

    2)执行慢开始算法,指数规律增长到第4轮,即cwnd=16=ssthresh,改为执行拥塞避免算法,拥塞窗口按线性规律增长

    3)假定cwnd=24时,网络出现超时(拥塞),则更新后的ssthresh=12,cwnd重新设置为1,并执行慢开始算法。当cwnd=12=ssthresh时,改为执行拥塞避免算法

    “拥塞避免”并非完全能够避免了阻塞,而是使网络比较不容易出现拥塞。

    方法二:快速重传、快速恢复

    在前面流量控制里讲过整个快速重传机制。 就是一个发送端的数据包丢失了,怎么才能快速识别出来已经丢失了呢? 而不是等待比较漫长的超时机制。 这个方法就是:发送端收到同一个确认包3次,就认为这个保丢失了。 这个机制就叫做快速重传机制

    根据上面的拥塞检测,快速重传后,慢启动门限阙值就要设置为拥塞窗口的一半。然后重新开始慢启动过程。

    快速恢复(fast revovery):

    当发送方连续收到三个重复确认时,就执行“乘法减小”算法,把ssthresh门限减半(为了预防网络发生拥塞)。但是接下去并不执行慢开始算法(a)而是拥塞避免算法。 这就是快速恢复算法

    (a)这里没有执行慢启动算法是因为:收到重复的ACK不仅仅告诉我们一个分组丢失了。由于接收端只有在收到另一个报文段时才会产生重复的ACK,而该报文段已经离开了网络并进入了接收方的缓冲区。也就是说,在收发两端仍然有数据流动,而我们不想执行慢开始算法来突然减少数据流。而是将cwnd设置为ssthresh减半后的值,然后执行拥塞避免算法,使cwnd缓慢增大。

    快速恢复算法出现在4.3BSD Reno版本中

    参考

  • 相关阅读:
    1697 ⑨要写信
    1220 数字三角形
    4979 数塔
    bzoj1618[Usaco2008 Nov]Buying Hay 购买干草
    bzoj1066[SCOI2007]蜥蜴
    bzoj1008[HNOI2008]越狱
    cf437D The Child and Zoo
    cf437C The Child and Toy
    cf437B The Child and Set
    cf437A The Child and Homework
  • 原文地址:https://www.cnblogs.com/jiujuan/p/12210218.html
Copyright © 2011-2022 走看看