为什么需要四次挥手?三次不行?
PS:这个问的太多了,大家要先理解 =》背诵,防止突然忘了也能说个大概。这道题在问的时候,可深可浅,看面试官自己的掌握力度。
四次挥手也一样,千万不要对方一个 FIN 报文,我方一个 ACK 报文,再我方一个 FIN 报文,我方一个 ACK 报文。然后结束,最好是说的详细一点,例如想下面这样就差不多了,要把每个阶段的状态记好,我上次面试就被问了几个了,呵呵。我答错了,还以为自己答对了,当时还解释的头头是道,呵呵。
刚开始双方都处于 establised 状态,假如是客户端先发起关闭请求,则:
1、第一次挥手:客户端发送一个 FIN 报文,报文中会指定一个序列号。此时客户端处于FIN_WAIT1状态。(大白话:相当于客户端告诉服务端,我想断开链接了)
2、第二次挥手:服务端收到 FIN 之后,会发送 ACK 报文,且把客户端的序列号值 + 1 作为 ACK 报文的序列号值,表明已经收到客户端的报文了,此时服务端处于 CLOSE_WAIT状态。(大白话:相当于,服务端告诉客户端,好的,我收到你的断开请求了)
3、第三次挥手:如果服务端也想断开连接了,和客户端的第一次挥手一样,发给 FIN 报文,且指定一个序列号。此时服务端处于 LAST_ACK 的状态。
4、第四次挥手:客户端收到 FIN 之后,一样发送一个 ACK 报文作为应答,且把服务端的序列号值 + 1 作为自己 ACK 报文的序列号值,此时客户端处于 TIME_WAIT 状态。需要过一阵子以确保服务端收到自己的 ACK 报文之后才会进入 CLOSED 状态
5、服务端收到 ACK 报文之后,就处于关闭连接了,处于 CLOSED 状态。
这里特别需要主要的就是TIME_WAIT这个状态了,这个是面试的高频考点,就是要理解,为什么客户端发送 ACK 之后不直接关闭,而是要等一阵子才关闭。这其中的原因就是,要确保服务器是否已经收到了我们的 ACK 报文,如果没有收到的话,服务器会重新发 FIN 报文给客户端,客户端再次收到 FIN 报文之后,就知道之前的 ACK 报文丢失了,然后再次发送 ACK 报文。
至于 TIME_WAIT 持续的时间至少是一个报文的来回时间。一般会设置一个计时,如果过了这个计时没有再次收到 FIN 报文,则代表对方成功就是 ACK 报文,此时处于 CLOSED 状态。(下面的面试题会给出更加具体的答复)
这里我给出每个状态所包含的含义,有兴趣的可以看看。
- LISTEN – 侦听来自远方TCP端口的连接请求;
- SYN-SENT -在发送连接请求后等待匹配的连接请求;
- SYN-RECEIVED – 在收到和发送一个连接请求后等待对连接请求的确认;
- ESTABLISHED- 代表一个打开的连接,数据可以传送给用户;
- FIN-WAIT-1 – 等待远程TCP的连接中断请求,或先前的连接中断请求的确认;
- FIN-WAIT-2 – 从远程TCP等待连接中断请求;
- CLOSE-WAIT – 等待从本地用户发来的连接中断请求;
- CLOSING -等待远程TCP对连接中断的确认;
- LAST-ACK – 等待原来发向远程TCP的连接中断请求的确认;
- TIME-WAIT -等待足够的时间以确保远程TCP接收到连接中断请求的确认;
- CLOSED – 没有任何连接状态;
下面是三次握手和四次挥手的图片
评论(16)
参照三次握手机制,挥手最少需要三次,如果只有三次,客户端发送完数据请求断开连接,而服务端不一定也同样发送完数据,若同时回ACK和FIN给客户端,断开连接,可能造成数据的损坏;若先发送ACK,再等B的数据发送完了再发送FIN和ACK,就可以保证传输数据的完整性。
tcp是全双工模式,接收到FIN意味着将没有数据再发来,但是还是可以继续发送数据。
第二次挥手中把客户端的序列号值 + 1 作为 ACK 报文的序列号值,应该是把客户端的序列号值 + 1 作为 ACK 报文中ack值吧
是滴
第二个次挥手
已修改,谢谢提醒
CLOSE_WAIT2应该改成CLOSE_WAIT吧,毕竟挥手过程中只有一次这个状态
已改,谢谢
好像有一种说法是其实三次挥手也可以?
理论上也是可以 三次挥手的,这块我找了挺多的答案参考的,各种说法都有,也有人通过抓包,也有三次挥手的,一种可能的原因就是 ACK+FIN 报文合并了,而且这个操作系统的实现可能也有细微的差别,具体你们可以看知乎的这个讨论:https://www.zhihu.com/question/50646354
很精炼,必学内容?
似乎还有被问到OSI七层模型的,也可以把这个题目加入进去。
已经补上了
帅地,客户端发送第一次FIN报文后,应该是处于FIN_WAIT1,而不是文中说的CLOSE_WAIT1?
已修改
这个问题到底应该是什么 我看原文还是CLOSE_WAIT1状态呀,没有修改呀
改了啊,,,,我看是已经改了