TCP使用三次握手和四次挥手来建立和终止连接

一、三个标志位

1. SYN(Synchronize)标志位:用于请求建立连接

2. ACK(Acknowledgement) 标志位:用于确认数据的传输。当成功接收到数据后,接收方发送一个带有 ACK 标志的报文段回复发送方,确认已经收到了数据。

3. FIN (Finish) 标志位:用于关闭连接

二、三次握手过程

1、握手前的初始状态

客户端: CLOSED ——> 发送 SYN后进入 SYN_SENT

服务器: CLOSED ——> 监听端口时处于 LISTEN

2、第一次握手(客户端发起)

客户端:

发送SYN报文

字段 说明
序列号 (seq) x 随机生成的ISN(如:1523123456)
确认号 (ack) 0 无效/未设置,因为这是首次发起连接
SYN标志位 1 这是SYN报文,SYN=1
ACK标志位 0 不是确认报文,所以ACK=0

进入 SYN_SENT 状态,等待服务器的 SYN+ACK

服务器:

仍处于 LISTEN 状态,等待连接请求

3、第二次握手(服务器响应)

服务器:

收到SYN报文后,发送SYN+ACK报文(是一条报文,同时设置了SYN和ACK两个标志位)

字段 说明
源端口 服务器的监听端口(如80)
目的端口 客户端的源端口
序列号 (seq) y 服务器的ISN(随机生成)
确认号 (ack) x+1 确认客户端的SYN,期待客户端发x+1
SYN标志位 1 这是服务器的SYN
ACK标志位 1 这是对客户端SYN的确认
其他标志位 都为0

进入 SYN_RCVD 状态,等待客户端的 ACK

客户端:

仍处于 SYN_SENT 状态,等待 SYN_ACK

4、第三次握手(客户端确认)

客户端:

收到 SYN+ACK 后,发送 ACK

字段 说明
源端口 客户端的源端口
目的端口 服务器的端口(如80)
序列号 (seq) x+1 客户端的下一个序号(因为SYN消耗了序号x)
确认号 (ack) y+1 确认服务器的SYN,期待服务器发y+1
SYN标志位 0 不是SYN报文
ACK标志位 1 这是确认报文
其他标志位 都为0
数据长度 0字节 纯ACK,不携带应用数据

进入 ESTABLISHED 状态

服务器:

收到 ACK后,进入 ESTABLISHED 状态

状态汇总表

步骤 客户端状态 服务器状态 说明
初始 CLOSED LISTEN 服务器监听端口
第一次握手 SYN_SENT LISTEN 客户端发送SYN
第二次握手 SYN_SENT SYN_RCVD 服务器发送SYN+ACK
第三次握手 ESTABLISHED ESTABLISHED 双方连接建立完成

三、三次握手的意义

1、投石问路,初步验证了网络通信路径是畅通的

2、验证通信双方的发送能力和接受能力是否正常

3、三次握手过程中,完成了一些参数协商

4、同步了双方的初始序列号

四、三次握手的几个常见问题

1、两次握手行不行

如图所示,缺少了最后一次握手,会导致无法验证客户端的接收数据的功能是否正常,所以不行

2、四次握手可不可以

如图,相对于三次握手来说,四次握手把第二次握手拆成了两次通信,可以看出,四次握手也可以实现三次握手所实现的功能,但是没有必要,效率比三次低

五、四次挥手的过程

主动关闭方和客户端/服务器角色没有必然联系,下图以客户端为主动关闭方为例

第一次挥手:主动关闭方发起

主动关闭方:

触发条件:应用层调用 close()

发送报文:构造并发送一个 FIN 报文

段名 值(十六进制/二进制) 说明
序列号(seq) u 最后一个应用数据字节的序号+1
确认号(ack) 当前期望接收的下一字节序号 这个值有意义!不是0
标志位 FIN=1, ACK=0或1 关键澄清

状态变化:状态由 ESTABLISHED 进入 FIN_WAIT_1(等待确认)

后续行为:停止发送引用层数据,但可以继续接受对方发来的数据,等待对方的 ACK 确认

被动关闭方:

收到 FIN 报文:从网卡接收到 FIN

内核处理:检查连接是否存在且有效、更新接收窗口,期望下一个字节序号改为 u+1

通知应用层: 如果由阻塞的 read() 操作,会返回 EOF(0)

状态变更:从 ESTABLISED 进入 CLOSED_WAIT(等待关闭)

理解现状:知道对方已经关闭了发送通道,自己仍可以向对方发送数据,连接进入半关闭状态

第二次挥手:被动关闭方确认

被动关闭方:

立即响应:收到 FIN 后,尽快发送 ACK

发送报文:构造 ACK 报文

字段名 说明
序列号(seq) v 被动方最后发送的应用数据字节序号+1
确认号(ack) u+1 关键值:确认主动方的FIN
标志位 ACK=1,其他全0 纯确认报文

应用层机会

在 CLOSE_WAIT 状态下,应用可以继续读取接受缓冲区、如果还有数据要发给主动发,现在可以发送、这是发送剩余数据的最后机会

准备关闭:应用层最终也会调用 close()

主动关闭方:

收到 ACK:确认对方已经收到自己的 FIN

状态变化:从 FIN_WAIT_1 进入  FIN_WAIT_2(等待对方关闭)

能力变化:完全不能发送数据,但仍可以接收对方发来的数据,仍处于单向接受状态

下一步等待:等待对方的 FIN 报文

第三次挥手:被动关闭方发起关闭

被动关闭方:

触发条件: 应用层调用 close() (数据已经发送完)

发送报文:构造 FIN 报文

ACK为1:再次确认"我知道你之前要关闭了"(ACK=1)

序列号可变(取决于 CLOSE_WAIT 期间是否发送数据)

确认号与第二次挥手相同(主动方在发送FIN后停止发送新数据)

字段名 说明
序列号(seq) w 被动方当前最后发送的字节序号+1
确认号(ack) u+1 关键值:依然确认主动方的初始FIN
标志位 FIN=1, ACK=1,其他全0 这是重点!

状态变更:从 CLOSE_WAIT 进入 LAST_ACK(最终确认)

最后清理:关闭自己的发送缓冲区,等待对方的最终确认

超时准备:如果没有收到 ACK,会重传 FIN

主动关闭方:

收到 FIN:知道对方也要关闭了

确认收到:需要响应这个 FIN

状态保持:   仍然在 FIN_WAIT_2状态(尚未变化)

准备确认:立即准备发送最后的 ACK

理解现状:知道双方都已同意关闭

第四次挥手:主动关闭方最终确认

主动关闭方:

立即响应:收到 FIN 后立即发送 ACK

发送报文:构造 ACK 报文

字段名 说明
序列号(seq) u+1 关键值:自己的初始FIN消耗了序列号u
确认号(ack) w+1 关键值:确认被动方的FIN
标志位 ACK=1,其他全0 纯确认报文

状态变更:从 FIN_WAIT_2 进入 TIME_WAIT(时间等待) ,启动 2MSL 定时器(MSL = 一个TCP报文段在网络中能够存活的最长时间)

TIME_WAIT 期间:不能立即关闭连接,如果收到对方的 FIN 重传(因ACK丢失),会重发 ACK,确保网络中的旧报文都过期

最终关闭:2MSL 超时后,进入 CLOSED 状态

被动关闭方:

收到 ACK:确认对方已经收到自己的 FIN

状态变更:从 LAST_ACK 进入 CLOSED

立即释放:立即释放所有资源,端口可以立即重用,连接完全终止

完成关闭:不会再有这个连接的任何状态

双方对比总结

挥手阶段 主动关闭方 被动关闭方
第一次挥手 发送FIN
进入FIN_WAIT_1
收到FIN
进入CLOSE_WAIT
第二次挥手 收到ACK
进入FIN_WAIT_2
发送ACK
保持CLOSE_WAIT
可发送剩余数据
第三次挥手 收到FIN
保持FIN_WAIT_2
发送FIN
进入LAST_ACK
第四次挥手 发送ACK
进入TIME_WAIT
等待2MSL
收到ACK
进入CLOSED

六、完整过程

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐