TIME_WAIT状态出现在服务器接受了大量连接 主动关闭连接的时候(一般是web服务器)
我之前用asio碰到过 大量连接 CLOSE_WAIT 状态 现在想想是没调用 socket_.shutdown(tcp::socket::shutdown::shutdown_both,ec);就直接析构了socket_ 具体原因是客户端请求关闭连接的时候 服务器在收到 FIN M 之后 没发送 ack M+1 和 FIN N 正确的关闭连接是: boost::system::error_code ec; socket_.cancel(ec); socket_.shutdown(tcp::socket::shutdown_both,ec); socket_.close(ec);
TIME_WAIT 是必然会出现的状态,是正常现象,且会定时回收
TIME_WAIT 状态持续2MSL时间,MSL就是maximum segment lifetime(最大报文段的生命期),这是一个IP数据包能在互联网上生存的最长时间,超过这个时间将在网络中消失(被丢弃)。RFC 793中规定MSL为2分钟,实际应用中,可能为30S,1分钟,2分钟。
与CLOSE_WAIT区别
一个是TIME_WAIT,一个是CLOSE_WAIT,完全不同的两个状态 TIME_WAIT 出现在主动断开方,发出最后一个ACK后 CLOSE_WAIT 出现在被动断开方,收到主动断开方的FIN,发出自己的ACK后
注意close() 和 shutdown()的区别
close()其实只是将socket fd的引用计数减1,只有当该socket fd的引用计数减至0时,TCP传输层才会发起4次握手从而真正关闭连接。而shutdown则可以直接发起关闭连接所需的4次握手,而不用受到引用计数的限制 close()会终止TCP的双工链路。由于TCP连接的全双工特性,可能会存在这样的应用场景:local peer不会再向remote peer发送数据,而remote peer可能还有数据需要发送过来,在这种情况下,如果local peer想要通知remote peer自己不会再发送数据但还会继续收数据这个事实,用close()是不行的,而shutdown()可以完成这个
解决办法
- 代码层修改,把短连接改为长连接,但代价较大
- 修改 ip_local_port_range,增大可用端口范围,比如1024 ~ 65535
- 客户端程序中设置socket的 SO_LINGER 选项
- 打开 tcp_tw_recycle 和tcp_timestamps 选项,有一定风险,且linux4.12之后被废弃
- 打开 tcp_tw_reuse 和 tcp_timestamps 选项
- 6设置 tcp_max_tw_buckets 为一个较小的值