文章目录
- 1 四次挥手
- 2 参数优化
- 2.1 tcp_orphan_retries--->FIN报文重传次数
- 2.2 tcp_max_orphans--->孤儿连接最大数量
- 2.3 tcp_fin_timeout--->FINE_WAIT2状态等待时间
- 2.4 tcp_max_tw_buckets
- 2.5 tcp_tw_reuse--->复用未释放的端口
- 3 总结
参考资料:
1. RFC793
在Client和Server断开连接时候,会经历四次交互,称为四次挥手,本篇简单介绍下四次交互。
1 四次挥手
如上图,客户端和服务端都可以主动先发起close操作,在这里,我们假设Client先发送close操作。
- 第一次交互:Client和Server都处于ESTABLISHED状态,正常进行通信,此时Client应用程序调用close()或shutdown()来关闭连接。那么内核就会发送FIN报文给到Server。此时Client的状态为FIN_WAIT1;
- 第二次交互:Server收到FIN报文后,内核自动回复ACK报文。此时Server的状态为CLOSE_WAIT,Client收到ACK之后,状态变为FIN_WAIT2;
- 第三次交互:Server应用程序调用close函数来关闭连接,并发送SIN报文,此时Server的状态为LAST_ACK;
- 第四次交互:Client收到FIN之后,回复ACK报文,状态变为TIME_WAIT,等待2MSL后,连接彻底关闭,Server收到ACK后会立马关闭连接。
2MSL的时长为30*2=60s,RFC793定义了MSL为2分钟,Linux设置成了30s,MSL是指报文在网络中的最长生存时间,之所以定义2MSL,是假设发送的ACK丢失,最大消耗一个MSL时间,然后Server端重发一次FIN报文,最大消耗一次MSL事件,那么此时出于TIME_WAIT状态的Client端收到FIN报文后仍然可以发送一次ACK,如果多次丢失,考虑到概率以及性能问题,直接忽略,即只考虑一次丢失。
等待2MSL时间,也不完全是为了数据的重发,而是一种安全保证。如果不等待,立马完全关闭,那么可能被应用程序里面使用这个端口,因为网络因素、Server端重发等因素可能会收到旧的重发的FIN报文,那么新的连接就会被被误关闭;并且也可以防止新的连接收到旧的数据,造成异常。
PS:有时候可能Server收到FIN报文之后,里面close掉,所以可能会出现ACK+FIN在同一个报文中,回复给Client,这时四次握手就变成三次握手了。
PPS:如果Client进程异常退出了,内核就会主动发送RST报文给到Server,然后直接关闭连接,不走正常的四次挥手流程。
2 参数优化
2.1 tcp_orphan_retries—>FIN报文重传次数
当第一次交互时候,如果Client发送FIN包后,一直没有收到Server的ACK,那么就会重发,重发次数受tcp_orphan_retries内核参数控制。
# cat /proc/sys/net/ipv4/tcp_orphan_retries
0
默认值为0,表示8次。如果此值大于0,则为正常重试的次数。
如果超过tcp_orphan_retries重试的次数,还没有收到ACK报文,则直接关闭连接。
在第三次交互中,如果Server发送FIN之后,没有收到ACK报文,也会重发,重发次数受tcp_orphan_retries参数控制。
2.2 tcp_max_orphans—>孤儿连接最大数量
当Client端应用程序调用close关闭连接后,此时这个连接已经和应用程序无关了,为孤儿进程,剩下的事由内核来发送FIN包,来和Server进行四次挥手。
那么如果此时发送缓冲区还有数据没有发送完,那么就需要等待发送完,才能把FIN报文发送出去,或者TCP的流控功能,当Server端将接收窗口为0,即Client端不能发送数据,那么Client的连接就会长时间处于FIN_WAIT1状态。
如果一个连接长时间处于FIN_WAIT1状态,就会导致系统资源被长时间占用,因此tcp_max_orphans 参数来定义最大的孤儿连接数量,如果数量大于此值,那么就会直接发送RST报文,不走正常四次握手流程。
# cat /proc/sys/net/ipv4/tcp_max_orphans
512
2.3 tcp_fin_timeout—>FINE_WAIT2状态等待时间
当Client收到ACK后,就处于FINE_WAIT2状态,等待Server的FIN报文,此时如果Client应用程序是调用shutdown关闭连接,则一直处于FINE_WAT2状态,在这种状态下,还可以收发数据;如果是调用close关闭的,那么如果超时没有收到FIN报文,就会直接关闭。超时时间受tcp_fin_timeout参数控制。
# cat /proc/sys/net/ipv4/tcp_fin_timeout
60
2.4 tcp_max_tw_buckets
Client处于TIME_WAIT状态下,会等待2MSL时间然后彻底关闭连接。但是这种状态也会导致系统资源被长时间占用,因此tcp_max_tw_buckets 参数来定义最大的TIME_WAIT状态的连接数量,如果数量大于此值,那么就会直接关闭,不再经历2MSL时间关闭。
# cat /proc/sys/net/ipv4/tcp_max_tw_buckets
512
2.5 tcp_tw_reuse—>复用未释放的端口
Client处于TIME_WAIT状态下,这个时候端口仍然被占用,因此应用程序无法使用此端口建立新的连接。因此,可通过tcp_tw_reuse参数来使能可以使用处于TIME_WAIT状态的端口。
# cat /proc/sys/net/ipv4/tcp_tw_reuse
0
0关闭,1使能。
另外,如果使能了这个功能,还需要打开TCP时间戳功能,并且需要双方都打开。
# cat /proc/sys/net/ipv4/tcp_timestamps
1