简述TCP三次握手和四次挥手流程

本文详细解析了TCP协议中的三次握手建立连接及四次挥手断开连接的过程,包括各阶段的状态变化、标志位作用及序号含义等内容。

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

前言

关于TCP的连接过程,很多从事程序开发的小伙伴应该都听过三次握手,可这三次握手的细节还是有很多人不太清楚的,特别是有些参数记不清楚,我也经常弄错,所以我根据自己的理解画了两张图,将TCP连接和断开的流程简单记录一下,以方便后续查找复习之用。

三次握手

tcp_connect

初始状态:客户端A和服务器B均处于CLOSED状态,然后服务器B创建socket,调用监听接口使得服务器处于LISTEN状态,等待客户端连接。(后续内容用A,B简称代替)

  1. A首先向B发起连接,这时TCP头部中的SYN标识位值为1,然后选定一个初始序号seq=x(一般是随机的),消息发送后,A进入SYN_SENT状态,SYN=1的报文段不能携带数据,但要消耗一个序号。

  2. B收到A的连接请求后,同意建立连接,向A发送确认数据,这时TCP头部中的SYN和ACK标识位值均为1,确认序号为ack=x+1,然后选定自己的初始序号seq=y(一般是随机的),确认消息发送后,B进入SYN_RCVD状态,与连接消息一样,这条消息也不能携带数据,同时消耗一个序号。

  3. A收到B的确认消息后,需要给B回复确认数据,这时TCP头部中的ACK标识位值为1,确认序号是ack=y+1,自己的序号在连接请求的序号上加1,也就是seq=x+1,此时A进入ESTABLISHED状态,当B收到A的确认回复后,B也进入ESTABLISHED状态,至此TCP成功建立连接,A和B之间就可以通过这个连接互相发送数据了。

四次挥手

tcp_disconnect
初始状态:客户端A和服务器B之间已经建立了TCP连接,并且数据发送完成,打算断开连接,此时客户端A和服务器B是等价的,双方都可以发送断开请求,下面以客户端A主动发起断开请求为例。(后续内容用A,B简称代替)

  1. A首先向B发送断开连接消息,这时TCP头部中的FIN标识位值为1,序号是seq=m,m为A前面正常发送数据最后一个字节序号加1得到的,消息发送后A进入FNI_WAIT_1状态,FIN=1的报文段不能携带数据,但要消耗一个序号。

  2. B收到A的断开连接请求需要发出确认消息,这时TCP头部中的ACK标识位值为1,确认号为ack=m+1,而自己的序号为seq=n,n为B前面正常发送数据最后一个字节序号加1得到的,然后B进入CLOSE_WAIT状态,此时就关闭了A到B的连接,A无法再给B发数据,但是B仍然可以给A发数据(此处存疑),同时B端通知上方应用层,处理完成后被动关闭连接。然后A收到B的确认信息后,就进入了FIN_WAIT_2状态。

  3. B端应用层处理完数据后,通知关闭连接,B向A发送关闭连接的消息,这时TCP头部中的FIN和ACK标识位值均为1,确认号ack=m+1,自己的序号为seq=k,(B发出确认消息后有发送了一段数据,此处存疑),消息发送后B进入LAST_ACK状态。

  4. A收到B的断开连接的消息后,需要发送确认消息,这是这时TCP头部中的ACK标识位值为1,确认号ack=k+1,序号为m+1(因为A向B发送断开连接的消息时消耗了一个消息号),然后A进入TIME_WAIT状态,若等待时间经过2MSL后,没有收到B的重传请求,则表明B收到了自己的确认,A进入CLOSED状态,B收到A的确认消息后则直接进入CLOSED状态。至此TCP成功断开连接。

总结

  1. 关于三次握手,参考了很多资料说服务器是被动打开连接,对此有些不解,希望知道的朋友给出提示和建议。

  2. 关于四次挥手,在我的叙述中有两处存疑,就是B收到的A的主动断开请求后,进入CLOSE_WAIT状态,是否还能发送数据到A,参考了一些资料说A不能发数据给B,但是B能发数据给A,并且A也可以接收,但是无论我在Windows环境测试还是Linux环境下测试这种状态A都无法收到B的数据,不知道我是不是理解错了,希望明白原理的小伙伴能解答一下。

  3. 在四次挥手的最后阶段,有一个等待时间2MSL,这个不是一个时间单位,而是一个表明时间段的名词,这段等待时间就是为了在B没收到确认消息时,接收B的重传请求的,如果不等待这一段时间直接进入CLOSED状态,那么B未收到A的确认消息就会发送重传请求,而此时A已经关闭,就不会再给B重传了,其中MSL的是Maximum Segment Lifetime英文的缩写,可简单译为“报文最大生存时间”,也就是说如果B没有收到确认信息,那么在2MSL这段时间内很大概率就会发送重传请求,并且被A收到,RFC 793中规定MSL为2分钟,实际应用中常用的是30秒,1分钟和2分钟等。

  4. 在连接和断开的过程都有提到ACKack,这一点要注意区分,大写的ACK代表TCP头部中6个标识位之一,是表明这是个确认报文,而小写的ack拜师确认序号,表明对方发来的数据到ack这个序号前的都已经收到了。

### TCP三次握手过程详解 TCP三次握手(Three-way Handshake)是建立TCP连接时的关键步骤,其目的是确保通信双方的发送接收能力正常,并协商初始化序列号确认号,以保证后续数据传输的可靠性。具体过程如下: 1. **第一握手**:客户端发送一个SYN标志位为1的报文段(SYN=1),并指定一个初始序列号(Sequence Number=x)。客户端进入SYN_SENT状态,表示请求建立连接。 2. **第二握手**:服务器接收到SYN报文后,会回应一个SYN-ACK报文段(SYN=1, ACK=1),其中ACK是对客户端SYN的确认(Acknowledgment Number=x+1),同时服务器也会发送自己的初始序列号(Sequence Number=y)。 3. **第三次握手**:客户端收到SYN-ACK后,向服务器发送一个ACK报文段(ACK=1),确认服务器的SYN(Acknowledgment Number=y+1),连接正式建立[^3]。 通过三次握手,客户端服务器可以互相确认彼此的发送接收能力是否正常,并交换序列号确认号信息,为后续数据传输做好准备。三次握手的设计还有效防止了已经失效的连接请求突然传送到服务器的情况,从而避免资源浪费错误[^5]。 ### TCP四次挥手过程详解 TCP四次挥手(Four-way Wavehand)是断开TCP连接的过程,其主要目的是确保连接断开时所有数据都能完整传输,并释放相关资源。具体过程如下: 1. **第一挥手**:客户端发送一个FIN标志位为1的报文段(FIN=1),表示自己已经没有数据要发送了,请求断开连接。客户端进入FIN_WAIT_1状态。 2. **第二挥手**:服务器接收到FIN后,会发送一个ACK报文段(ACK=1)作为响应,确认客户端的FIN请求(Acknowledgment Number=Sequence Number+1)。服务器进入CLOSE_WAIT状态,客户端进入FIN_WAIT_2状态。 3. **第三次挥手**:服务器完成数据传输后,也会发送一个FIN报文段(FIN=1),表示自己准备断开连接。服务器进入LAST_ACK状态。 4. **第四次挥手**:客户端接收到服务器的FIN后,发送一个ACK报文段(ACK=1)作为确认,进入TIME_WAIT状态。服务器收到ACK后,连接正式关闭。客户端在等待一段时间(通常是2MSL,Maximum Segment Lifetime)后,确认服务器收到了ACK,最终关闭连接[^2]。 四次挥手的设计确保了通信双方都能安全地关闭连接,避免了数据丢失或重复传输的问题。 ### TCP连接建立与断开的关键机制 - **防止失效连接请求**:三次握手可以防止已失效的连接请求突然传送到服务器,从而避免资源浪费。如果采用两握手,客户端发送的旧请求可能在网络中延迟后到达服务器,导致服务器误认为客户端要重新建立连接[^5]。 - **全双工通信的关闭**:由于TCP是全双工通信协议,连接的每一方都需要独立关闭发送方向的数据流。因此,在四次挥手中,客户端服务器各自发送FINACK,确保双向连接都能正确关闭。 ### 示例代码:TCP连接的建立与断开 以下是一个简单的Python示例,展示如何使用`socket`库建立断开TCP连接: ```python import socket # 创建客户端socket client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 连接到服务器 server_address = ('localhost', 8080) client_socket.connect(server_address) print("已建立连接") # 发送数据 client_socket.sendall(b'Hello, server!') # 关闭连接 client_socket.close() print("已关闭连接") ``` 在服务器端,可以使用以下代码监听连接并处理客户端的请求: ```python import socket # 创建服务器socket server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 绑定地址端口 server_address = ('localhost', 8080) server_socket.bind(server_address) # 开始监听 server_socket.listen(1) print("等待连接...") # 接受连接 client_socket, client_address = server_socket.accept() print(f"连接来自: {client_address}") # 接收数据 data = client_socket.recv(1024) print(f"收到数据: {data}") # 关闭连接 client_socket.close() print("已关闭连接") ``` ###
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AlbertS

常来“玩”啊~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值