1 概述

  • TCP提供可靠的运输层。
  • 可靠性保证之一:确认从另一端收到的数据。
  • 但数据和确认都有可能会丢失。TCP通过在发送时设置一个定时器来解决这种问题。
  • 如果当定时器溢出时还没有收到确认,它就重传该数据。
  • TCP对于每个连接TCP管理4个不同的定时器:
    • 重传定时器:使用于当希望收到另一端的确认。
    • 2MSL定时器:测量一个连接处于TIME_WAIT状态的时间。
    • 坚持(persist)定时器:使窗口大小信息保持不断流动,即使另一端关闭了其接收窗口
    • 保活(keepalive)定时器:用于检测一个空闲连接的另一端何时崩溃或重启。

2 TCP的状态机

TCP协议探究(二):超时与重试-LMLPHP

超时情况

  • 建立连接时SYN超时

    • client主动打开连接,发送SYN报文给server
    • server收到后被动打开,发送SYN+ACK报文给client,此时client直接下线
    • 导致server无法收到client的ACK报文,即该TCP连接既没有建立也没有断开,所以server又会重传SYN+ACK报文
    • 在Linux下,默认重试次数为5次,重试的间隔时间从1s开始每次都翻倍,5次的重试时间间隔为1s, 2s, 4s, 8s, 16s,总共31s,第5次发出后还要等32s都知道第5次也超时了,所以,总共需要 1s + 2s + 4s+ 8s+ 16s + 32s = 2^6 -1 = 63s,TCP才会把断开这个连接。
  • SYN Flood

    • 恶意伪造大量的TCP连接并断开Client,导致Server维持了大量的TCP连接,且需要63秒后才会断开,即63秒内的TCP连接数足够多时,Server将承受不住,导致正常的连接不能处理。
    • 处理方案:
      • 减少Server的重试次数
      • 增大SYN的连接数
      • 处理不过来的连接直接丢弃
  • ISN的初始化

    • ISN不是每次建立建立连接时都从1开始
    • 问题:因为如果从1开始,client发送了30个segment给server,此时网络断开,过会client重连,又使用ISN=1来发送报文,但之前的报文已经送到了,即server认为client的ISN(初始化序列号)为30,但是实际上为1。
    • 解决方法:ISN会和一个假的时钟绑在一起,这个时钟会在每4微秒对ISN做加一操作,直到超过2^32,又从0开始。
    • MSL(Maximum Segment Lifetime):TCP段的最大存活时间,4ms*2^32=4.55小时,即TCP段存活时间不超过4.55小时就不会重用ISN。
  • MSL 和 TIME_WAIT:

    • 在TCP的状态图中,从TIME_WAIT状态到CLOSED状态,有一个超时设置,这个超时设置是 2 * MSL。
    • TIME_WAIT(2 * MSL):确保有足够的时间让对端收到了ACK,如果被动关闭的那方没有收到Ack,就会触发被动端重发FIN,一来一去正好不超过2 * MSL。
    • 有足够的时间让这个连接不会跟后面的连接混在一起(有些路由器会缓存IP数据包,导致连接被重用)。

3 TCP重试机制(发送方)

(1)概述

TCP要保证所有的数据包都到达,必需有重传机制。

发送端发了1,2,3,4,5一共五份数据,接收端收到了1,2,于是回ack 3,然后收到了4(注意此时3没收到),此时的TCP会怎么办?

(2)超时重传机制

  • 不回ACK,一直等待SN=3的到来,而发送方一直收不到3的ACK,就会超时重传3.
  • 这种方式会有严重的问题,那就是死等3,所以导致4和5已经被收到了,而发送方也完全不知道(没有收到ACK),所以发送方可能会悲观地认为也丢了(即有可能导致4和5的重传)。
  • 发送方的两种选择
    • 仅仅重传timeout的包,节约宽带,但是需要继续等待后续报文ACK或者timeout重传(效率低)。
    • 重传timeout后的所有包,浪费宽带,而且可能做了无用功。

(3)快速重传机制

  • 如果发送方发出了1,2,3,4,5份数据,1先到了,于是就ack回2,结果2因为某些原因没收到。3到达了,ack也回2,后面的4和5都到了,ack也回2(2没有收到)。
  • 于是发送端收到了三个ack=2的确认,知道了2还没有送达,于是重传2(或者2之后的所有包)。然后接收端收到了2,此时3,4,5都收到了,于是ack回6。
  • 优点:不需要等待ACK超时,但是仍然没有解决是重传2还是重传2与之后的所有包。

(4)SACK 方法

TCP协议探究(二):超时与重试-LMLPHP

  • SACK回复可以告知发送端需要排除哪些报文进行发送
  • 该协议需要两边都支持。

强烈建议看看TCP协议探究(二):超时与重试-LMLPHP叔的文章

参考:https://coolshell.cn/articles/11564.html

05-26 08:54