TCP四次挥手关闭读写通道

本文详细阐述了TCP连接关闭的过程,包括四次挥手的具体步骤及其背后的原理,解释了为何需要TIME_WAIT状态及2MSL时间间隔,同时给出了客户端与服务器在连接关闭过程中的状态迁移图。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

第一种解释:

TCP协议的连接是全双工连接,一个TCP连接存在双向的读写通道。 

简单说来是 “先关读,后关写”,一共需要四个阶段。以客户机发起关闭连接为例:
1.服务器读通道关闭
2.客户机写通道关闭
3.客户机读通道关闭
4.服务器写通道关闭
关闭行为是在发起方数据发送完毕之后,给对方发出一个FIN(finish)数据段。直到接收到对方发送的FIN,且对方收到了接收确认ACK之后,双方的数据通信完全结束,过程中每次接收都需要返回确认数据段ACK。
详细过程:
    第一阶段   客户机发送完数据之后,向服务器发送一个FIN数据段,序列号为i;
    1.服务器收到FIN(i)后,返回确认段ACK,序列号为i+1,关闭服务器读通道;
    2.客户机收到ACK(i+1)后,关闭客户机写通道;
   (此时,客户机仍能通过读通道读取服务器的数据,服务器仍能通过写通道写数据)
    第二阶段 服务器发送完数据之后,向客户机发送一个FIN数据段,序列号为j;
    3.客户机收到FIN(j)后,返回确认段ACK,序列号为j+1,关闭客户机读通道;
    4.服务器收到ACK(j+1)后,关闭服务器写通道。
这是标准的TCP关闭两个阶段,服务器和客户机都可以发起关闭,完全对称。

FIN标识是通过发送最后一块数据时设置的,标准的例子中,服务器还在发送数据,所以要等到发送完的时候,设置FIN(此时可称为TCP连接处于半关闭状态,因为数据仍可从被动关闭一方向主动关闭方传送)。如果在服务器收到FIN(i)时,已经没有数据需要发送,可以在返回ACK(i+1)的时候就设置FIN(j)标识,这样就相当于可以合并第二步和第三步。

第二种解释:

TCP状态迁移
大家对netstat -a命令很熟悉,但是,你有没有注意到STATE一栏呢,基本上显示着established,time_wait,close_wait等,这些到底是 什么意思呢,在这篇文章,我将会详细的阐述。
大家很明白TCP初始化连接三次握手吧:发SYN包,然后返回SYN/ACK包,再发ACK包,连接正式建立。但是这里有点出入,当请求者收到SYS /ACK包后,就开始建立连接了,而被请求者第三次握手结束后才建立连接。但是大家明白关闭连接的工作原理吗?关闭连接要四次握手:发FIN包,ACK 包,FIN包,ACK包,四次握手!!为什么呢,因为TCP连接是全双工,我关了你的连接,并不等于你关了我的连接。

客户端TCP状态迁移:
CLOSED->SYN_SENT->ESTABLISHED->FIN_WAIT_1->FIN_WAIT_2->TIME_WAIT->CLOSED
服务器TCP状态迁移:
CLOSED->LISTEN->SYN收到 ->ESTABLISHED->CLOSE_WAIT->LAST_ACK->CLOSED

当客户端开始连接时,服务器还处于LISTENING,
客户端发一个SYN包后,他就处于SYN_SENT状态,服务器就处于SYS收到状态,
然后互相确认进入连接状态ESTABLISHED.


当客户端请求关闭连接时,客户端发送一个FIN包后,客户端就进入FIN_WAIT_1状态,等待对方的确认包,
服务器发送一个ACK包给客户,客户端收到ACK包后结束FIN_WAIT_1状态,进入FIN_WAIT_2状态,等待服务器发过来的关闭请求,
服务器发一个FIN包后,进入CLOSE_WAIT状态,
当客户端收到服务器的FIN包,FIN_WAIT_2状态就结束,然后给服务器端的FIN包给以一个确认包,客户端这时进入TIME_WAIT,
当服务器收到确认包后,CLOSE_WAIT状态结束了,
这时候服务器端真正的关闭了连接.但是客户端还在TIME_WAIT状态下,

从以上TCP连接关闭的状态转换图可以看出,主动关闭的一方在发送完对对方FIN报文的确认(ACK)报文后,
会进入TIME_WAIT状态。TIME_WAIT状态也称为2MSL状态。
为什么要设置这个状态,原因是有足够的时间让ACK包到达服务器端,如果服务器端没收到ACK包,超时了,然后重新发一个FIN包,直到服务器收到ACK 包.

什么是2MSL?MSL即Maximum Segment Lifetime,也就是报文最大生存时间,引用<TCP/IP详解>中的话:“
它(MSL)是任何报文段被丢弃前在网络内的最长时间。”那么,2MSL也就是这个时间的2倍。其实我觉得没
必要把这个MSL的确切含义搞明白,你所需要明白的是,当TCP连接完成四个报文段的交换时,主动关闭的
一方将继续等待一定时间(2-4分钟),即使两端的应用程序结束。你可以写代码试试,然后用netstat查看下。

为什么需要2MSL?根据<TCP/IP详解>和<The TCP/IP Guide>中的说法,有两个原因:
其一,保证发送的ACK会成功发送到对方,如何保证?我觉得可能是通过超时计时器发送。这个就很难用
代码演示了。

下图是四次挥手状态转换图:




TCP连接断开图:


### TCP 三次握手原因解释 TCP三次握手过程是为了建立可靠的连接,其核心目的是为了双方能够同步初始序列号 (ISN),并确认彼此的接收能力和发送能力。以下是具体原因: - **防止历史请求干扰新连接**:如果仅通过两次握手来建立连接,则可能存在旧的重复请求到达服务器的情况,从而引发错误连接[^1]。第三次握手的作用在于验证客户端确实收到了服务器发来的 SYN+ACK 报文,并有能力响应。 - **同步初始序列号**:在第一次握手中,客户端随机生成一个初始序列号 ISN 并将其发送给服务端;第二次握手中,服务端返回自己的 ISN 同时确认收到客户端的 ISN;第三次握手中,客户端再次确认接收到的服务端 ISN。这样就完成了双向的序列号同步。 ```python # 客户端发起SYN请求 client.send(SYN) # 服务端回应SYN+ACK server.receive(SYN) server.send(SYN_ACK) # 客户端确认ACK client.receive(SYN_ACK) client.send(ACK) ``` --- ### TCP 四次挥手原因解释 四次挥手的过程用于优雅地关闭已有的 TCP 连接,主要原因是 TCP 是全双工通信模式,因此需要分别结束两个方向上的数据传输。 - **独立关闭读写通道**:当一方希望关闭连接时,它会先发送 FIN 包表示自己不再发送数据,但仍可继续接受对方的数据。另一方收到 FIN 后也会回复 ACK 表示已经知晓该消息[^2]。此时只是单向关闭完成,直到第二方也决定停止发送数据再发出自己的 FIN 包,最终形成完整的四步流程。 - **确保未送达数据被处理完毕**:即使某一方准备断开连接,在此之前可能还有部分缓冲区中的数据尚未完全传递到对端。通过分两阶段(FIN 和 ACK)逐步通知的方式可以保障这些残留数据有机会得到妥善处置[^3]。 ```plaintext Client Server | | -----> FIN | Client wants to close connection. |<----- ACK | Server acknowledges the request. | | |------> ACK | Client confirms receipt of server's acknowledgment. |<----- FIN | Server also wishes to terminate its side. |------> ACK | Final confirmation from client, now both sides are closed. | ``` --- ### 总结对比 - **三次握手的核心目标**是实现可靠连接的确立以及初始化必要的参数交换; - 而 **四次挥手中的额外一次交互** 则是因为要考虑到网络延迟下可能出现的部分数据未能及时传达的情形,保证整个通讯链路彻底安全解除前没有任何遗漏的信息丢失风险存在。 #### 关键点回顾 - 只有经过三个回合才能真正建立起稳定有效的逻辑信道关系。 - 断连操作则需四个步骤来充分照顾到各自状态转换期间的各种可能性变化情况。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值