Skip to content

Network 的一些补充 #7

@shadw3002

Description

@shadw3002
  1. 三次握手一方面是为了交换编号,另一方面是为了确认双方的收发能力均无碍
  2. SYN Flood 攻击就是针对半连接队列的,不过也有叫 SYN Cookie 的方法使得不需要半连接队列保存状态
  3. 粘包这个说法是对 TCP 的 misunderstanding,TCP 是面向字节流的,不是面向包的
  4. 拥塞控制的补充:
  • 流控制
    流控制是通过发送方的 =SWS= 实现的,流控制有两个方面:流量控制和拥塞控制。

流量控制的相关变量是接收方给发送方的 =AdvWin=,拥塞控制的相关变量是发送方的 =CongWin=。

这两个量决定发送方的 =SWS=,即 SWS = min(AdvWin,CongWin)

** 流量控制
流量控制是为防止发送方发的太快,耗尽接收方的资源,从而使接收方来不及处理。

方法:

  • 接收端一旦发现自己的缓冲区快满了,就会将窗口大小设置成一个更小的值通知给发送端,发送端收到这个值后,就会减慢自己的发送速度。
  • 如果接收端发现自己的缓冲区满了,就会将窗口的大小设置为 0 ,此时发送端将不再发送数据,但是需要定期发送一个窗口探测数据段,使接收端把窗口大小告诉发送端。

** 拥塞控制

  • 拥塞控制 :: 防止发送方发的太快,使得网络来不及处理,从而导致网络拥塞

#+attr_org: :width 600px
[[file:tcp_congestion_control.png]]

*** 表现

  • 丢包 (路由器上缓冲区溢出)
  • 长延迟 (在路由器缓冲区中排队)

*** 发送端如何知道

  • 定时器超时
  • 收到三个重复 ACK

*** TCP 拥塞控制
超时或收到 3 个重复ack就认为丢包了,看作拥塞发生了。

TCP协议通过减少发送速率来控制拥塞。发送速率与发送窗口大小有关:

发送速率 rate = SWS(Sending Window Size)/RTT

引入 拥塞窗口变量 CongWin来 限制SWS

SWS = Min(CongWin, AdvWin)

TCP 拥塞控制方法都是改变 CongWin 的。

*** 慢启动——Tahoe 算法

  • 初始时,CongWin 设为 1 MSS ,设定一个慢启动阈值(ssthresh),发送一个数据段。
  • 每收到一个 ACK ,CongWin 就增加一个 MSS。
  • 在当前窗口所有数据段的确认都收到之后,CongWin 加倍。
    • 当 CongWin 增长到等于或大于 ssthresh 时, 转入拥塞避免算法。
    • 即每个 RTT CongWin 加倍。

#+begin_example
假设Tahoe算法被用于TCP连接的拥塞控制, 当超时发生时, CongWin等于16MSS, 如果期间没有发生超时,在5个RTT之后CongWin是多少?

Answer:
10MSS

Explanation:
2mss,4Mss,8mss,9mss,10Mss
#+end_example

*** 拥塞避免——加性增乘性减(Additive Increase Multiplicative Decrease ,AIMD)

  • 加性增 (additive increase) :: 每次收到一个确认将 CongWin 增加 SegSize/CongWin ,即每个 RTT CongWin 增加 1MSS 。
  • 乘性减 (multiplicative decrease) :: 拥塞发生时(超时或重复确认), ssthresh 设置为当前窗口大小(SWS)的一半(但不得小于 2 报文段)。

#+begin_example

  1. 如果AIMD(Additive Increase Multiplicative Decrease)用于TCP连接的拥塞控制, 当发生拥塞时, CongWin=10MSS, 它的新的CongWin是多少?在4个RTT之后, 它的CongWin又是多少?
    Answer:
    5MSS 9MSS
    #+end_example

乘性减,若是超时引起,则 CongWin 从 1MSS 开始,并重新进行慢开始阶段。若是重复 ACK 引起,则进行快速重传流程。拥塞避免对超时反应比较强烈。

从整体上来讲,TCP 拥塞控制窗口变化的原则是 AIMD 原则,即加法增大、乘法减小。可以看出 TCP 的该原则可以较好地保证流之间的公平性,因为一旦出现丢包,那么立即减半退避,可以给其他新建的流留有足够的空间,从而保证整个的公平性。

*** 快速重传与快速恢复——Reno算法
快速重传:

  1. 把 ssthresh 降低为 CongWin 值的一半
  2. 把 CongWin 设置为 sshresh 的值(某些实现为 sshresh+3)
  3. 重新进入拥塞避免阶段。

后来的“快速恢复”算法是在上述的“快速重传”算法后添加的,当收到 3 个重复 ACK 时,TCP 最后进入的不是拥塞避免阶段,而是快速恢复阶段。快速重传和快速恢复算法一般同时使用。快速恢复的思想是“数据包守恒”原则,即同一个时刻在网络中的数据包数量是恒定的,只有当“老”数据包离开了网络后,才能向网络中发送一个“新”的数据包,如果发送方收到一个重复的 ACK,那么根据 TCP 的 ACK 机制就表明有一个数据包离开了网络,于是 cwnd 加 1。如果能够严格按照该原则那么网络中很少会发生拥塞,事实上拥塞控制的目的也就在修正违反该原则的地方。

快速恢复:

  • 当收到 3 个重复的 ACK 时,将 ssthresh 设置为 Congwin 的一半。重传丢失的报文段。设置 CongWin 为 ssthresh 加上 3 倍的报文段大小。加 3 的原因是因为收到 3 个重复的 ACK,表明有 3 个“老”的数据包离开了网络。
  • 每次收到另一个重复的 ACK 时,CongWin 增加 1 个报文段大小并发送 1 个分组(如果新的 CongWin 允许发送)。
  • 当下一个确认新数据的 ACK 到达时,设置 CongWin 为 ssthresh (在第 1 步中设置的值)。这个 ACK 应该是在进行重传后的一个往返时间内对步骤 1 中重传的确认。另外,这个 ACK 也应该是对丢失的分组和收到的第 1 个重复的 ACK 之间的所有中间报文段的确认。

#+begin_example
假设Reno算法(快速恢复算法)被用于TCP连接的拥塞控制, 当收到三个重复的ACK时, CongWin等于16MSS, 如果期间没有发生超时,在5个RTT之后CongWin是多少?

Answer:
13MSS

Explanation:
9MSS,10MSS,11MSS,12MSS,13MSS
#+end_example

*** New Reno
可以看出Reno的快速重传算法是针对一个包的重传情况的,然而在实际中,一个重传超时可能导致许多的数据包的重传,因此当多个数据包从一个数据窗口中丢失时并且触发快速重传和快速恢复算法时,问题就产生了。因此NewReno出现了,它在Reno快速恢复的基础上稍加了修改,可以恢复一个窗口内多个包丢失的情况。具体来讲就是:Reno在收到一个新的数据的ACK时就退出了快速恢复状态了,而NewReno需要收到该窗口内所有数据包的确认后才会退出快速恢复状态,从而更一步提高吞吐量。

这个算法是Reno算法的改进,没有使用SACK机制

  • 当sender这边收到了3个Duplicated Acks,进入Fast Retransimit模式,开始重传重复Acks指示的那个包。如果只有这一个包丢了,那么,重传这个包后回来的Ack会把整个已经被sender传输出去的数据ack回来。如果没有的话,说明有多个包丢了。我们叫这个ACK为Partial ACK。
  • 一旦Sender这边发现了Partial ACK出现,那么sender就可以推理出来有多个包被丢了,于是乎继续重传sliding window里未被ack的第一个包。直到再也收不到了Partial Ack,才真正结束Fast Recovery这个过程

*** SACK
SACK就是改变TCP的确认机制,最初的TCP只确认当前已连续收到的数据,SACK则把乱序等信息会全部告诉对方,从而减少数据发送方重传的盲目性。比如说序号1,2,3,5,7的数据收到了,那么普通的ACK只会确认序列号4,而SACK会把当前的5,7已经收到的信息在SACK选项里面告知对端,从而提高性能,当使用SACK的时候,NewReno算法可以不使用,因为SACK本身携带的信息就可以使得发送方有足够的信息来知道需要重传哪些包,而不需要重传哪些包。

*** 重新分组
当 TCP 超时并重传时,它不一定要重传同样的报文段。相反,TCP 允许进行重新分组而发送一个较大的报文段,这将有助于提高性能(当然,这个较大的报文段不能够超过接收方声明的 MSS)。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions