zoukankan      html  css  js  c++  java
  • TCP拥塞控制原理

    一、何为拥塞

    路由器无法处理高速到达的数据而被迫丢弃数据的现象叫做拥塞。

    二、何为拥塞控制

    TCP流量控制时为了平衡一个链接中接收方和发送方的速度匹配问题,当发送方发现发送速度大于接收方的接收速度时动态调整发送速度。

    但是成千上万的TCP链接共享着整个网络基础设施,当网络上这些TCP都在传输数据时,网络有可能就会拥塞,TCP的拥塞控制就是在传输自己数据的同时实时掌握整个网络的负载,然后基于整个网络的负载来动态调整自己的发送速度。

    三、网络拥塞的开销

    拥塞时路由器丢失数据,丢失后基于可靠性传输的机制,发送方会重传数据,重传会再次加大网络负载,导致更大的开销。

    在多路由器的情况下,会导致更大的资源浪费,比如数据有A传递到B经过了三个路由器,结果被第三个路由器给丢弃了。这样前两个路由器的工作全被白白浪费。如下图所示,R3拥塞,A--》B的数据到达R3之后最终被丢弃了,R1、R2的工作被白白浪费。

    由此可见,拥塞控制势在必行。

    四、拥塞控制的基本方法

    4.1 端到端的拥塞控制

    网络层不提供拥塞控制机制,主要依靠端系统对网络的观察来调整发送的速度最终完成拥塞的控制(比如端系统通过观察丢包的情况来判断)。TCP/IP就是通过端到端的方法来解决拥塞控制(让TCP来控制,IP不管)。

    核心:观察,感知,调整,解决。TCP的拥塞控制方法。

    4.2 网络辅助的拥塞控制

     由路由器告知发送方网络是否拥塞,主要两种:

    1. 路由器直接高速发送方网络状况
    2. 当发送拥塞时,路由器在当前报文中标识拥塞,当接收方拿到这个拥塞标识后,由接收方告知发送方网络拥塞,这种方式至少要一个RTT发送方才能知道拥塞。

    报文不详细展开。

    五、TCP拥塞控制方法

    TCP拥塞控制属于端到端的控制方法,其核心便是观察感知网络的拥塞状态,然后调整发送速度。在TCP中引入了拥塞窗口(cwnd:congestion window),流量控制中引入了接收窗口(rwnd:receive window)。最终TCP的发送窗口为min{cwnd,rwnd}。

    5.1 如何感知网络?

    对于TCP来说核心两点:

    1. 丢包(超时,或者三次冗余ack)就代表网络拥塞,需要减少cwnd的size。
    2. 确认代表网络畅通,可以加大cwnd的size。确认的越快cwnd增加的越快(反之亦然)。自计时(self-clocking)

    下面的即将要介绍的几个方法都是基于上面的两个核心来展开的。

    5.2 慢启动(Slow Start)

    慢启动就是TCP启动后的发送速度慢慢的进行提速,这样才能便于感知网络的状况。

    慢启动的核心算法:

    1. 刚开始cwnd=1个MSS(max segment size)
    2. 每当收到一个ack,cwnd=cwnd+1。这样每过一个RTT。cwnd便会翻倍:cwnd=cwnd*2,这是指数级增加
    3. 当cwnd=ssthresh(慢启动阈值,slow start threshold)时,停止指数级增加,进入避免拥塞流程。

    5.3 拥塞避免

    慢启动时cwnd时指数级增长,当增长的到ssthresh后便进入避免拥塞。避免拥塞算法比较简单:

    1. 每收到一个ack,cwnd=cwnd+1/cwnd;
    2. 由此可见,每过一个RTT。cwnd=cwnd+1

    可见拥塞避免算法实际是将cwnd的增长由指数级增长变为了一个线性缓慢增长。如下图所示。

    5.4 拥塞发生(感知到拥塞)

    TCP认为发生拥塞由两种情况:

    • 超时
    • 收到连续三次相同的ACK(快速重传的场景)

    5.4.1 超时

    TCP超时后的具体动作:

    • ssthresh=cwnd/2
    • cwnd=1
    • 进入慢启动流程

    5.4.2 连续三次相同的ACK

    • 进入快速恢复流程

    5.5 快速恢复

     收到三次连续相同的ACK,说明产生了丢包,但是能收到ACK,说明超时相对不是那么严重。所以针对这种情况,TCP的做法没有超时那么激进:

    • ssthresh=cwnd
    • cwnd=cwnd/2+3,3代表连续收到了3个ACK,累加三个窗口大小。
    • 进入拥塞避免流程

     以上介绍了TCP拥塞控制的一个整体过程。本文完。

  • 相关阅读:
    百度统计
    类的成员函数指针和mem_fun适配器的用法
    使用RTTI为继承体系编写”==”运算符
    Linux组件封装(五)一个生产者消费者问题示例
    Linux组件封装(四)使用RAII技术实现MutexLock自动化解锁
    模板系列(一)模板的模板参数
    Linux组件封装(三)使用面向对象编程封装Thread
    Linux组件封装(二)中条件变量Condition的封装
    Linux组件封装(一)中互斥锁MutexLock的封装
    迭代器适配器(二)general inserter的实现
  • 原文地址:https://www.cnblogs.com/Brake/p/13908384.html
Copyright © 2011-2022 走看看