本帖最后由 Hacking 于 2022-5-11 11:54 编辑
当一台主机操作系统主动关闭TCP Endpoint(socket)时,该TCP Endpoint进入TW状态。以Windows为例,Windows内核会对 TCP Endpoint 数据结构进行相应清理,然后放入额外的 TIME_WAIT queue 中,设置2MSL 的定时器,等待定时器超时后调用对应的释放代码。Linux上的实现也是类似。目前较多的说法是"TCP连接"进入TW ,但我们可能需要理解 "连接" 其实是抽象的概念。实际上"连接"在逻辑上存在,因为客户端和服务器端以及中间可能涉及的4层设备同时为一次传输创建了关联的TCP资源(Endpoint,或者 Session)。准确理解TW状态,即TCP EndpointTIME_WAIT进入TIME_WAIT状态。
1)可靠地实现TCP全双工连接的终止
在进行关闭连接四次挥手协议时,最后的ACK是由主动关闭端发出的,如果这个最终的ACK丢失,服务器将重发最终的FIN,因此客户端必须维护状态信息允许它重发最终的ACK。如果不维持这个状态信息,那么客户端将响应RST分节,服务器将此分节解释成一个错误(在java中会抛出connection reset的SocketException)。
因而,要实现TCP全双工连接的正常终止,必须处理终止序列四个分节中任何一个分节的丢失情况,主动关闭的客户端必须维持状态信息进入TIME_WAIT状态。
2)允许老的重复分节在网络中消逝
TCP分节可能由于路由器异常而“迷途”,在迷途期间,TCP发送端可能因确认超时而重发这个分节,迷途的分节在路由器修复后也会被送到最终目的地,这个原来的迷途分节就称为lost duplicate。
在关闭一个TCP连接后,马上又重新建立起一个相同的IP地址和端口之间的TCP连接,后一个连接被称为前一个连接的化身(incarnation),那么有可能出现这种情况,前一个连接的迷途重复分组在前一个连接终止后出现,从而被误解成从属于新的化身。为了避免这个情况,TCP不允许处于TIME_WAIT状态的连接启动一个新的化身,因为TIME_WAIT状态持续2MSL,就可以保证当成功建立一个TCP连接的时候,来自连接先前化身的重复分组已经在网络中消逝。
存在即是合理的,在高并发短连接的TCP服务器上,当服务器处理完请求后立刻主动正常关闭连接。这个场景下会出现大量socket处于TIME_WAIT状态。如果客户端的并发量持续很高,此时部分客户端就会显示连接不上。我来解释下这个场景。主动正常关闭TCP连接,都会出现TIMEWAIT。
查询TCP连接数,统计TIME_WAIT 连接的本地地址
- netstat -ant|awk '/^tcp/ {++S[$NF]} END {for(a in S) print (a,S[a])}'
- LAST_ACK 14
- SYN_RECV 348
- ESTABLISHED 70
- FIN_WAIT1 229
- FIN_WAIT2 30
- CLOSING 33
- TIME_WAIT 18122
复制代码- CLOSED:无连接是活动的或正在进行
- LISTEN:服务器在等待进入呼叫
- SYN_RECV:一个连接请求已经到达,等待确认
- SYN_SENT:应用已经开始,打开一个连接
- ESTABLISHED:正常数据传输状态
- FIN_WAIT1:应用说它已经完成
- FIN_WAIT2:另一边已同意释放
- ITMED_WAIT:等待所有分组死掉
- CLOSING:两边同时尝试关闭
- TIME_WAIT:另一边已初始化一个释放
- LAST_ACK:等待所有分组死掉
复制代码
- <div><ul><li>编辑内核文件/etc/sysctl.conf,加入以下内容:</li></ul></div><div>
- </div><div>net.ipv4.tcp_syncookies = 1 表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭;
- 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 时间</div><div>
- </div><div>然后执行 /sbin/sysctl -p 让参数生效.</div><div>
- </div><div><ul><li>清理TIME_WAIT脚本</li></ul>
- cat >> /etc/sysctl.conf << EOF
- net.ipv4.tcp_tw_reuse=1
- net.ipv4.tcp_tw_recycle=1
- net.ipv4.tcp_fin_timeout=30
- EOF
- sysctl -p
- </div><div>
- </div><div>
- </div>
复制代码
|