文章持续更新,可以微信搜一搜「小白 debug」第一时间阅读,回复【面试】获面试题集。本文已经收录在 GitHub https://github.com/xiaobaiTech/golangFamily , 有大厂面试完整考点和成长路线,欢迎 Star。
搬运一个在某乎的回答,水一篇文章吧。
正常情况下。只要数据传输完了,不管是客户端还是服务端,都可以主动发起四次挥手,释放连接。
就跟上图画的一样,假设,这次四次挥手是由客户端主动发起的,那它就是主动方。服务器是被动接收客户端的挥手请求的,叫被动方。
客户端和服务器,一开始,都是处于ESTABLISHED
状态。
第一次挥手:一般情况下,主动方执行close()
或 shutdown()
方法,会发个FIN报文
出来,表示”我不再发送数据了“。
第二次挥手:在收到主动方的FIN
报文后,被动方立马回应一个ACK
,意思是”我收到你的 FIN 了,也知道你不再发数据了”。
上面提到的是主动方不再发送数据了。但如果这时候,被动方还有数据要发,那就继续发。注意,虽然第二次和第三次挥手之间,被动方是能发数据到主动方的,但主动方能不能正常收就不一定了,这个待会说。
第三次挥手:在被动方在感知到第二次挥手之后,会做了一系列的收尾工作,最后也调用一个 close()
, 这时候就会发出第三次挥手的 FIN-ACK
。
第四次挥手:主动方回一个ACK
,意思是收到了。
其中第一次挥手和第三次挥手,都是我们在应用程序中主动触发的(比如调用close()
方法),也就是我们平时写代码需要关注的地方。
第二和第四次挥手,都是内核协议栈自动帮我们完成的,我们写代码的时候碰不到这地方,因此也不需要太关心。
另外不管是主动还是被动,每方发出了一个 FIN
和一个ACK
。也收到了一个 FIN
和一个ACK
。
回到题主的问题。
TCP 四次挥手中如果服务端没收到第四次挥手请求,服务端会一直等待吗?
第四次挥手是第三次挥手触发的。如果第四次挥手服务端一直没收到,那服务端会认为是不是自己的第三次挥手丢了,于是服务端不断重试发第三次挥手(FIN).重发次数由系统的 tcp_orphan_retries 参数控制。重试多次还没成功,服务端直接断开链接。所以结论是服务端不会一直等待第四次挥手。
1 | cat /proc/sys/net/ipv4/tcp_orphan_retries |
另外,你会发现tcp_orphan_retries
参数是 0,但其实并不是不重试的意思。为 0 时,默认值为 8. 也就是重试 8 次。
1 | /* Calculate maximal number or retries on an orphaned socket. */ |
当然如果服务端重试发第三次挥手 FIN 的过程中,还是同样的端口和 IP,起了个新的客户端,这时候服务端重试的 FIN 被收到后,客户端就会认为是不正常的数据包,直接发个 RST 给服务端,这时候两端连接也会断开。
参考资料
查资料的时候发现小林大佬已经写过,而且写的巨好,感兴趣的可以看下他的这篇文章。
链接太长,懒得复制的话,点击阅读原文可以直接跳转。
最后
新的文章快写好了,就缺个开头了。
我有个不成熟的请求。
离开广东好长时间了,好久没人叫我靓仔了。
大家可以在评论区里,叫我一靓仔吗?
我这么善良质朴的愿望,能被满足吗?
如果实在叫不出口的话,能帮我点下右下角的点赞和在看吗?
别说了,一起在知识的海洋里呛水吧
点击下方名片,关注公众号:【小白 debug】
不满足于在留言区说骚话?
加我,我们建了个划水吹牛皮群,在群里,你可以跟你下次跳槽可能遇到的同事或面试官聊点有意思的话题。就超!开!心!
