TCP TIME_WAIT状态

TCP的TIME_WAIT 状态

什么是TIME_WAIT状态

  • TCP的TIME_WAIT是指在四次挥手中,主动断开方 在收到对方发送的FIN后,向对方发送ACK后就会进入TIME_WAIT状态
  • 处于TIME_WAIT状态时,端口被占用,无法创建新连接
  • 只有等待2MSL(报文在网络中的最大生存时间)后,才会进入CLOSED状态
  • TIME_WAIT状态一般是主动断开的一方

TIME_WAIT存在的原因

  • 可以确保全双工连接中断: 如果客户端发送的最后一次ACK丢失,此时服务器端就会重新发送,此时如果客户端处于close状态,就无法再次收到服务器端的FIN。就无法完成四次挥手。
  • 保证可以接收未到达的数据被接收或消失,
    因为处于TIME_WAIT状态时,端口仍然被占用,如果没有TIME_WAIT状态,使用该端口下一个服务器就会收到之前仍在网络中传播的数据,从而会导致服务器发生错误。所以需要TIME_WAIT的时间来接收还未到达的数据。也防止重传的FIN影响新的连接。

TIME_WAIT为什么要2MSL时间

  • 等待2MSL的时间的作用就是让重传的FIN 和 未到达的数据被接收或消失
  • 是2MSL时间的是因为, 报文在网络中传送的最大的网络时间是MSL ,假如最后一个ACK丢失,被动断开方就会重新发送FIN ,这样最后一个ACK可在网络中生存的时间是MSL ,而重发的FIN可在网络中生存的时间也是MSL 所以两个加起来就是2MSL
[wens@localhost Socks5Sever2]$ cat /proc/sys/net/ipv4/tcp_fin_timeout
60

如何在服务器解决不能立即重启TIME_WAIT端口被占用的问题

  • 可以同个使用setsockopt函数,使其端口可复用
 可以通过setsockopt()实现端口的复用
第三个参数使用SO_REUSEADDR
int val = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &val , sizeof(val))
  • 修改内核的参数 处理TIME_WAIT状态
  • net.ipv4.tcp_tw_recycle 回收TIME_WAIT
tcp_tw_recycle = 0

尽量不要使用,可能存在问题
- 当多个客户端通过NAT联网访问服务器,服务器看到的是同一个IP ,也就啊是对于服务器端来说,这些客户端
等同与同一个,由于这些客户端的时间戳会不同,所以在服务器看来可能会出现时间戳错乱的问题,会导致时
间戳较小的包被丢弃。

- 建议不要使用该选项,现在使用互联网NAT的有很多,可能会导致无法进行三次握手,无法进行连接
原因: 
开启后在3.5*RTO(RTO时间是根据RTT时间计算而来)内回收TIME_WAIT,并60s内同一源ip主机的socket 
connect请求中的timestamp必须是递增的,对于服务端,同一个源ip可能会是NAT后很多机器,这些机器timest
amp递增性无可保证,服务器会拒绝非递增请求连接,直接导致不能三次握手。

  • net.ipv4.tcp_tw_reuse 复用TIME_WAIT 连接
顾名思义就是复用TIME_WAIT连接。当创建新连接的时候,如果可能的话会考虑复用相应的TIME_WAIT连接。通常认为tcp_tw_reuse比tcp_tw_recycle安全一些,这是因为一来TIME_WAIT创建时间必须超过一秒才可能会被复用;二来只有连接的时间戳是递增的时候才会被复用。官方文档里是这样说的:如果从协议视角看它是安全的,那么就可以使用。这简直就是外交辞令啊!按我的看法,如果网络比较稳定,比如都是内网连接,那么就可以尝试使用。

不过需要注意的是在哪里使用,既然我们要复用连接,那么当然应该在连接的发起方使用,而不能在被连接方使用。举例来说:客户端向服务端发起HTTP请求,服务端响应后主动关闭连接,于是TIME_WAIT便留在了服务端,此类情况使用tcp_tw_reuse是无效的,因为服务端是被连接方,所以不存在复用连接一说。让我们延伸一点来看,比如说服务端是PHP,它查询另一个MySQL服务端,然后主动断开连接,于是TIME_WAIT就落在了PHP一侧,此类情况下使用tcp_tw_reuse是有效的,因为此时PHP相对于MySQL而言是客户端,它是连接的发起方,所以可以复用连接。

说明:如果使用tcp_tw_reuse,请激活tcp_timestamps,否则无效。

tcp_timestamps = 1
tcp_tw_reuse = 1
  • tcp_max_tw_buckets
顾名思义就是控制TIME_WAIT总数。官网文档说这个选项只是为了阻止一些简单的DoS攻击,平常不要人为的降低它。如果缩小了它,那么系统会将多余的TIME_WAIT删除掉,日志里会显示:TCP: time wait bucket table overflow。

需要提醒大家的是物极必反,曾经看到有人把「tcp_max_tw_buckets」设置成0,也就是说完全抛弃TIME_WAIT,这就有些冒险了,用一句围棋谚语来说:入界宜缓。

当出现TCP: time wait bucket table overflow时,尽量调大下面参数:

tcp_max_tw_buckets = 256000


TCP: time wait bucket table overflow产生原因及影响:原因是当TIME_WAIT数超过了Linux系统的TW数量的阈值。危害是超过阈值后,系统会把多余的TIME_WAIT Socket删除掉,并且显示警告信息。如果是NAT网络且又存在大量访问时,会产生各种连接不稳定断开的情况


tcp_fin_timeout = 15;这个参数是用来设置保持在FIN_WAIT_2状态的时间。tcp4此挥手,正常的处理流程就是在FIN_WAIT_2情况下接收到FIN进入到TIME_WAIT的情况,tcp_fin_timeout参数对处于TIME_WAIT状态的时间没有任何影响。但是如果这个参数设的比较小,会缩短从FIN_WAIT_2到TIME_WAIT的时间,从而使连接更早地进入TIME_WAIT状态。状态开始的早,等待相同的时间,结束的也早,客观上也加速了TIME_WAIT状态套接字的清理速度。

https://blog.csdn.net/cheng_fangang/article/details/49778161

出现服务器大量的TIME_WAIT状态的原因
  • 由于服务器主动断开连接,所以服务器就会进入TIME_WAIT装态
  • 查看当前连接有多少TIME_WAIT数命令
 #netstat -n | awk '/^tcp/ {++S[$NF]} END { for(a in S) print(a,S[a])}'
 

你可能感兴趣的:(Linux,计算机网络)