TCP 为每条连接建立了 7 个定时器:

  1. 连接建立定时器
  2. 重传定时器
  3. 延迟 ACK 定时器
  4. PERSIST 定时器
  5. KEEPALIVE 定时器
  6. FIN_WAIT_2 定时器
  7. TIME_WAIT 定时器

连接建立定时器(connection establishment)

当发送端发送 SYN 报文想建立一条新连接时,会开启连接建立定时器,如果没有收到对端的 ACK 包将进行重传。

image.png

  • 6 次重试以后放弃重试,connect 调用返回 -1,调用超时
  • 这个值是由 /proc/sys/net/ipv4/tcp_syn_retries 决定的

image.png

重传定时器(retransmission)

如果在发送数据包的时候没有收到 ACK 呢?这就是这里要讲的第二个定时器重传定时器。重传定时器在之前的文章中有专门一篇文章介绍,重传定时器的时间是动态计算的,取决于 RTT 和重传的次数。

image.png

  • 重传时间间隔是指数级退避,直到达到 120s 为止
  • 重传次数是15次(这个值由操作系统的 /proc/sys/net/ipv4/tcp_retries2 决定),总时间将近 15 分钟。

image.png

延迟 ACK 定时器

在 TCP 收到数据包以后在没有数据包要回复时,不马上回复 ACK。这时开启一个定时器,等待一段时间看是否有数据需要回复。如果期间有数据要回复,则在回复的数据中捎带 ACK,如果时间到了也没有数据要发送,则也发送 ACK。在 Centos7 上这个值为 40ms

image.png

坚持计时器(persist timer)

Persist 定时器是专门为零窗口探测而准备的。我们都知道 TCP 利用滑动窗口来实现流量控制,当接收端 B 接收窗口为 0 时,发送端 A 此时不能再发送数据,发送端此时开启 Persist 定时器,超时后发送一个特殊的报文给接收端看对方窗口是否已经恢复,这个特殊的报文只有一个字节。

image.png

保活定时器(keepalive timer)

如果通信以后一段时间有再也没有传输过数据,怎么知道对方是不是已经挂掉或者重启了呢?于是 TCP 提出了一个做法就是在连接的空闲时间超过 2 小时,会发送一个探测报文,如果对方有回复则表示连接还活着,对方还在,如果经过几次探测对方都没有回复则表示连接已失效,客户端会丢弃这个连接。

image.png

FIN_WAIT_2 定时器

四次挥手过程中,主动关闭的一方收到 ACK 以后从 FIN_WAIT_1 进入 FIN_WAIT_2 状态等待对端的 FIN 包的到来,FIN_WAIT_2 定时器的作用是防止对方一直不发送 FIN 包,防止自己一直傻等。

  • 这个值由 /proc/sys/net/ipv4/tcp_fin_timeout 决定,在我的 Centos7 机器上,这个值为 60s

image.png

TIME_WAIT 定时器

TIME_WAIT 定时器也称为 2MSL 定时器,可能是这七个里面名气最大的,主动关闭连接的一方在 TIME_WAIT 持续 2 个 MSL 的时间,超时后端口号可被安全的重用。

image.png

TIME_WAIT存在的意义有两个:

  • 可靠的实现 TCP 全双工的连接终止(处理最后 ACK 丢失的情况)
  • 避免当前关闭连接与后续连接混淆(让旧连接的包在网络中消逝)