TCP四次挥手之FIN_WAIT_2和CLOSE_WAIT
我们回顾下使用的抓包 1.1. 服务器未开 客户端尝试连接
1.2 建立连接然后关闭,断开的时候时候有时候三次握手有时候四次握手
1.3. 建立连接,交互一次然后断开
根据的包,四会握手的第二步 被动断开的一方收到FIN(第一次握手)后要发送ACK。但是抓的包中有时候会没有这一步。
我们看一下一般的书中TCP四次挥手的状态迁移图
当被动断开的一方发送ACK的时候,被动断开的
对于这个图大家很熟悉。
按照这个图的顺序说明会误导大家以为断开一个TCP总是这样的。其实按照的描述将主动断开的一方和被动断开的一方分开描述会更清晰。
2. TCP断开连接 2.1 主动断开的一方
①首先发送FIN告诉对方我要关闭连接,自己进入到状态此时开始不再处理和发送应用层用户的数据。
③收到对方对FIN的ACK后自己进入到,这个时候依然可以接收对方的数据。如果收不到对方的ACK会再次发送之前包含FIN在内的消息。进入后就等待对方关闭,因为已经确认到对方收到自己的FIN了。
⑤收到对方的FIN说明被断开的一方也要没有数据发送并关闭连接了,此时ACK对方的FIN进入。然后等2msl连接关闭。
–需要注意的是,对方ACK自己的FIN后,并不会立即发送FIN而是在应用层关闭连接后才会发送FIN
2.2被动断开的一方
②收到网络中传来的FIN,自己ACK这个FIN然后进入到状态。
④通知应用层要关闭连接(从这个角度上理解为什么断开比建立连接多了一次,因为被断开一方还有余下的数据要发送)这个时候等待用户来回应CLOSE,在发送FIN之前可以发送自己余下的数据。发送FIN后进入。
⑧等待对方ACK自己的FIN**完成关闭。如果对方没确认会再次发送**FIN。
2.3 断开过程的一些解释
(1)所以谁发送FIN谁就不再发送数据了。
(2)发送ACK的时候,ack是收到的req的值+1。因此第3和第4步的ack都是101。第四步并不是102。
(3)发送的seq是对方发送的ack所以第5步的seq是101而是不是102。
(4)第2步后主动断开放进入是等待对方的FIN。此时不可以发送数据但是可以接收数据。因此FIN意味着告诉对方“我没有多余的数据要发送”。这也是为什么断开比建立连接多一次的原因。因为发送FIN后还可以接收数据。
(5)被断开的一方收到FIN后,给对方发送ACK表示收到,自己状态为。此时TCP连接处于半关闭状态。被断开的一方仍然可以发送数据。这时候由上一层协议应用层来决定是否要发送余下的数据。
3. 为什么四次挥手?
我们看下断开连接的部分
3.1 实际中还会遇到的同时断开的情况和三次握手的情况 3.1.1 同时断开,同时发送FIN
同时断开的情况上面这张图是官方图。大家可以看到后还可能先收到FIN而不是ACK。why?因为两端可以同时关闭。同时收到对方的FIN然后同时确认直接进入->->流程。
3.12 三次握手,发送FIN后收到(FIN,ACK)
这张图还缺少一个状态转换就是直接收到(FIN,ACK)后到达。这种情况是被断开的一端没有数据要发送直接发送了ACK和FIN。这种情况通过抓包发现很常见。也就是四个过程也变为了三次握手。
这个还可能跟TCP的阻塞控制有关。
3.2 对于出现大量的
java 1042 root 42u IPv4 826784 0t0 TCP iZ2zei0nwllapkwklisoncZ:38250->100.100.18.22:squid (CLOSE_WAIT)
这个阶段对于被断开的一方还没有发送FIN连接处于半连接状态。但是如果的应用层并没有进close(这是个主动操作)不进入怎么办?
这种问题的出现举个往往是程序员的代码有问题。出现异常没有写关闭连接。
但是依然可以vim /etc/.conf设置超时时间,参数是net.ipv4.默认是2个小时。
net.ipv4.tcp_keepalive_time=7200
3.3 出现大量的
主动断开端此时等待FIN处于半连接状态。对于主动断开的一端而言,到是通过重发解决肯定回到但是到如果收不到对方的FIN怎么办?此不能重发,这个地方是通过超时解决
对于被断开的一端而言,这种勤快(2msk)和可以设置超时时间net.ipv4.
[root@iZ2zei0nwllapkwklisoncZ data]# /sbin/sysctl -a | grep timeout
net.ipv4.tcp_fin_timeout = 60
其中net.ipv4.就是的超时时间可以在
vim /etc/.conf设置。
3.4 出现(2msl)出现,以及这个状态的意义,msl是多长时间
状态,必须在此状态上停留两倍的msl时间,等待2msl时间主要目的是怕最后一个ACK包对方没收到,那么对方在超时后将重发第三次握手的FIN包,主动关闭端接到重发的FIN包后可以再发一个ACK应答包。在状态 时两端的端口不能使用,要等到2msl时间结束才可继续使用。当连接处于2msl等待阶段时任何迟到的报文段都将被丢弃。如果出现大量的。可以设置vim /etc/.conf来缩短msl的时间。总之到和到达之前收发两端的端口都是不可用的。会占用系统资源。
一个msl在的建议是2分钟,只是建议值
The TCP specification [TCP:1] arbitrarilyassumes a value of 2 minutes for MSL
另外介绍个内核参数net.ipv4. = 5000能容纳多少个超过后清除,以防止系统拖死。
3.5 收不到ACK如何关闭
会重发FIN,这时候分两种情况
(1)主动断开的一方还在状态中。这时候会发过来ACK, 被断开的一方收到后顺利从进入到。
(2)主动断开的一方经过了2msl已经了这时候会返回RST。被断开的一方收到后也会进入状态。总之总会进入到状态不需要超时机制。
4. 其他的内核参数
# 能容纳多少个TIME_WAIT超过后清除,以防止系统拖死
net.ipv4.tcp_max_tw_buckets = 5000
#对于一个新建连接,内核要发送多少个 SYN 连接请求才决定放弃
net.ipv4.tcp_syn_retries=6
#net.ipv4.tcp_synack_retries=2
#表示当keepalive起用的时候,TCP发送keepalive消息的频度。缺省是2小时
net.ipv4.tcp_keepalive_time=7200
net.ipv4.tcp_orphan_retries=3
#表示如果套接字由本端要求关闭,这个参数决定了它保持在FIN-WAIT-2状态的时间
net.ipv4.tcp_fin_timeout=60
#表示SYN队列的长度,默认为1024,加大队列长度为8192,可以容纳更多等待连接的网络连接数。
net.ipv4.tcp_max_syn_backlog = 4096
#表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭
net.ipv4.tcp_syncookies = 1#表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭
net.ipv4.tcp_tw_reuse = 1
#表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭
net.ipv4.tcp_tw_recycle = 1##减少超时前的探测次数
net.ipv4.tcp_keepalive_probes=5
##优化网络设备接收队列
net.core.netdev_max_backlog=3000