TCP协议之四次挥手

4 篇文章 0 订阅

四次挥手的目的

1.关闭客户端与服务端直接的双向通道

四次挥手的过程

1.当主动方关闭连接时,会发送FIN报文,此时发送方的TCP连接将从ESTABLISHED变成FIN_WAIT1。

2.当被动方收到FIN报文后,内核会自动回复ACK报文,连接状态将从ESTABLISHED变成CLOSE_WAIT,表示被动方在等待进程调用close函数关闭连接。

3.当主动方收到这个ACK后,连接状态由FIN_WAIT1变为FIN_WAIT2,也就是表示主动方的发送通道就关闭了。

4.当被动方进入CLOSE_WAIT时,被动方还会继续处理数据,等到进程的read函数返回0后,应用程序就会调用close函数,进而触发内核发送FIN报文,此时被动方的连接状态变为 LAST_ACK。

5.当主动方收到这个FIN报文后,内核会回复ACK报文给被动方,同时主动方的连接状态由FIN_WAIT2变为TIME_WAIT,在Linux系统下大约等待1分钟后,TIME_WAIT状态的连接才会彻底关闭。

6.当被动方收到最后的ACK报文后,被动方的连接就会关闭

在这里插入图片描述
注意:
1.通常先关闭连接的一方称为主动方,后关闭连接的一方称为被动方。
2.四次挥手过程只涉及了两种报文,分别是FIN和ACK。其中FIN就是Finish结束连接的意思,谁发出FIN报文,就表示它将不再发送任何数据,关闭这一方向的传输通道。ACK是Acknowledge确认的意思,它用来通知对方:你方的发送通道已经关闭。
3.主动关闭连接的,才有TIME_WAIT状态

主动方优化

关闭的连接的方式通常有两种,分别是RST报文关闭和FIN报文关闭。

如果进程异常退出了,内核就会发送RST报文来关闭,它可以不走四次挥手流程,是一个暴力关闭连接的方式。

安全关闭连接的方式必须通过四次挥手,它由进程调用close和shutdown函数发起FIN报文(shutdown参数须传入SHUT_WR或者SHUT_RDWR才会发送FIN)。区别在于close调用后,哪怕对方在半关闭状态下发送的数据到达主动方,进程也无法接收。

FIN_WAIT1状态的优化

参数:

net.ipv4.tcp_orphan_retries
	主动方发送FIN报文后,连接就处于FIN_WAIT1状态下,该状态通常应在数十毫秒内转为FIN_WAIT2。只有迟迟收不到对方返回的ACK时,可以用netstat -anpt | grep FIN_WAIT1来查看,(注意,orphan虽然是孤儿的意思,该参数却不只对孤儿连接有效,事实上,它对所有FIN_WAIT1状态下的连接都有效),默认值是 0,特指8次

net.ipv4.tcp_max_orphans
	定义了孤儿连接的最大数量。当进程调用close函数关闭连接后,无论该连接是在FIN_WAIT1状态,还是确实关闭了,这个连接都与该进程无关了,它变成了孤儿连接。Linux系统为防止孤儿连接过多,导致系统资源长期被占用,就提供了tcp_max_orphans参数。如果孤儿连接数量大于它,新增的孤儿连接将不再走四次挥手,而是直接发送RST复位报文强制关闭。
FIN_WAIT2状态的优化

参数:

net.ipv4.tcp_fin_timeout
	当主动方连接收到ACK进入FIN_WAIT2状态后,就表示主动方的发送通道已经关闭,接下来将等待对方发送FIN报文,关闭对方的发送通道。这时,如果连接是用shutdown函数关闭的,连接可以一直处于FIN_WAIT2状态。但对于close函数关闭的孤儿连接,这个状态不可以持续太久,而tcp_fin_timeout控制了这个状态下连接的持续时长。它的默认值是60秒。这意味着对于孤儿连接,如果60秒后还没有收到FIN报文,连接就会直接关闭。这个值与TIME_WAIT状态的持续时间是相同的
TIME_WAIT状态的优化

TIME_WAIT是主动方四次挥手的最后一个状态。当主动方收到被动方发来的FIN报文后,主动方会立刻回复ACK,表示确认对方的发送通道已经关闭,接着就处于 TIME_WAIT状态。在Linux系统,TIME_WAIT状态会持续60秒(2个MSL)后才会进入关闭状态。

TIME_WAIT状态的连接,在主动方看来确实已经关闭了。然而,被动方没有收到ACK报文前,连接还处于LAST_ACK状态。如果这个ACK报文没有到达被动方,被动方就会重发 FIN 报文。重发次数仍然由前面介绍过的tcp_orphan_retries参数控制。

如果主动方不保留TIME_WAIT状态,会发生什么呢?此时连接的端口恢复了自由身,可以复用于新连接了。然而,被动方的FIN报文可能再次到达,这既可能是网络中的路由器重复发送,也有可能是被动方没收到ACK时基于tcp_orphan_retries参数重发。这样,正常通讯的新连接就可能被重复发送的FIN报文误关闭。保留TIME_WAIT状态,就可以应付重发的FIN报文,当然,其他数据报文也有可能重发,所以TIME_WAIT状态还能避免数据错乱。

参数:

net.ipv4.tcp_max_tw_buckets
	当服务器的并发连接增多时,相应地,同时处于TIME_WAIT状态的连接数量也会变多,此时就应当调大该参数值,减少不同连接间数据错乱的概率。当然,该值也不是越大越好,毕竟内存和端口号都是有限的。
	
net.ipv4.tcp_tw_reuse与net.ipv4.tcp_timestamps
	如果服务器会主动向上游服务器发起连接的话,就可以把tcp_tw_reuse参数设置为1,它允许作为客户端的新连接,在安全条件下使用TIME_WAIT状态下的端口。要想使tcp_tw_reuse生效,还得把timestamps参数设置为1。

主动方优化

被动关闭的连接方应对非常简单,它在回复ACK后就进入了CLOSE_WAIT状态,等待进程调用close函数关闭连接。因此,出现大量CLOSE_WAIT状态的连接时,应当从应用程序中找问题。

当被动方发送FIN报文后,连接就进入LAST_ACK状态,在未等到ACK时,会在net.ipv4.tcp_orphan_retries参数的控制下重发FIN报文。

参考文档

1.https://time.geekbang.org/column/article/238388
2.https://mp.weixin.qq.com/s/Jgo_P1oKRHffurkoek0oVw
3.https://time.geekbang.org/course/detail/100026801-128141

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值