1. TCP连接建立和释放过程
建立的时候三次握手,释放的时候,四次挥手
time wait 状态不止一个
2. MSL
报文最大生存时间(Max Segment Lifetime),报文超过此时间就会被丢弃。
3. 为什么需要有time wait 状态?
1.可靠地实现TCP全双工连接的终止
TCP协议在关闭连接的四次握手过程中,最终的ACK是由主动关闭连接的一端(后面统称A端)发
出的,如果这个ACK丢失,对方(后面统称B端)将重发出最终的FIN,因此A端必须维护状态信息
(TIME_WAIT)允许它重发最终的ACK。如果A端不维持TIME_WAIT状态,而是处于CLOSED 状
态,那么A端将响应RST分节,B端收到后将此分节解释成一个错误(在java中会抛出connection
reset的SocketException)。
因而,要实现TCP全双工连接的正常终止,必须处理终止过程中四个分节任何一个分节的丢失情
况,主动关闭连接的A端必须维持TIME_WAIT状态 。
维护状态信息,从而在收到重传的FIN时候可以进行ACK消息的重发。
2. 消除前一次Tcp报文残留的影响
假设目前连接的通信双方都已经调用了close(),双方同时进入CLOSED的终结状态,而没有走
TIME_WAIT状态。会出现如下问题,现在有一个新的连接被建立起来,使用的IP地址与端口与先
前的完全相同,后建立的连接是原先连接的一个完全复用。还假定原先的连接中有数据报残存于网
络之中,这样新的连接收到的数据报中有可能是先前连接的数据报。为了防止这一点,TCP不允许
新连接复用TIME_WAIT状态下的socket。处于TIME_WAIT状态的socket在等待两倍的MSL时间以
后(之所以是两倍的MSL,是由于MSL是一个数据报在网络中单向发出到认定丢失的时间,一个数
据报有可能在发送途中或是其响应过程中成为残余数据报,确认一个数据报及其响应的丢弃的需要
两倍的MSL),将会转变为CLOSED状态。这就意味着,一个成功建立的连接,必然使得先前网
络中残余的数据报都丢失了。
4. 服务器CLOSE_WAIT状态过多
参考:http://elf8848.iteye.com/blog/1739571
CLOSE_WAIT是被动结束服务的那一端的状态,如果一直保持在CLOSE_WAIT状态,那么只有一
种情况,就是在对方关闭连接之后服务器程
序自己没有进一步发出ack信号。换句话说,就是在对方连接关闭之后,程序里没有检测到,或者
程序压根就忘记了这个时候需要关闭连接,于是这个资源就一直
被程序占着。
5. TCP连接中TIME_WAIT状态过多
参考: http://blog.csdn.net/yusiguyuan/article/details/21445883
高并发短连接的TCP服务器上,当服务器处理完请求后立刻按照主动正常关闭连接。。。这个场景
下,会出现大量socket处于TIMEWAIT状态。如果客户端的并发量持续很高,此时部分客户端就会显示连接不上。
sysctl改两个内核参数就行了,如下:
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
简单来说,就是打开系统的TIMEWAIT重用和快速回收,至于怎么重用和快速回收,这个问题我没
有深究,实际场景中这么做确实有效果。用netstat或者ss观察就能得出结论。
还有些朋友同时也会打开syncookies这个功能,如下:
net.ipv4.tcp_syncookies = 1
打开这个syncookies的目的实际上是:“在服务器资源(并非单指端口资源,拒绝服务有很多种资
源不足的情况)不足的情况下,尽量不要拒绝TCP的syn(连接)请求,尽量把syn请求缓存起来,
留着过会儿有能力的时候处理这些TCP的连接请求”。
如果并发量真的非常非常高,打开这个其实用处不大。
调整内核参数
net.ipv4.tcp_tw_reuse = 1 表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭;
net.ipv4.tcp_tw_recycle = 1 表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。
net.ipv4.tcp_fin_timeout 修改系統默认的 TIMEOUT 时间