三次握手与四次挥手
关键字
- ACK,即 Acknowledge characte,确认字符;
- SYN,即 Synchronize Sequence Numbers,同步序列编号;
- FIN ,即 Finish,结束;
- 客户端,发送请求的一端;
- 服务器,返回响应的一端。
握手与挥手的目的
握手也就是客户端与服务器进行连接,为实现后面信息的交互;
挥手也就是客户端与服务器断开连接,实现资源的释放。
三次握手
未建立连接之前, 服务器 处于 LISTEN 状态,服务器 准备就绪,允许 客户端 随时来建立连接
一次握手:客服端发送 SYN 给服务器尝试连接
二次握手:服务器返回 SYN + ACK
此时 客户端 收到 服务器 返回的 ACK 代表 服务器 已经知道 客户端 想要和他建立连接。
此时,客户端 对自己与 服务器 的认知:
客户端 的 发送能力 正常
客户端 的 接收能力 正常
服务器 的 发送能力 正常
服务器 的 接收能力 正常
但是, 服务器 对自己与 客户端 的认知:
客户端 的 发送能力 正常
客户端 的 接收能力 未知
服务器 的 发送能力 未知
服务器 的 接收能力 正常
所以此时 客户端 还需要返回一个 ACK 来让 服务器 对自己的 发送能力 和 客服端 的 接收能力 的认知,因此有了 三次握手。
三次握手:客户端返回 ACK 给服务器
当 服务器 收到 客户端 发送的 ACK 后,就知道自己的 接受能力 是 OK 的。
此时 客户端 和 服务器 都知道双方的 接受能力 和 发送能力 是 OK 的,接下来就可以进行 传输数据了。
此时 客户端 和 服务器 的状态都是 ESTABLISHED(stable 稳定的),表示连接建立成功,可以进行通信。
为什么要三次握手?两次握手可以吗?四次握手可以吗?
三次握手的原因 前面已经解释过,确保双方的 发送能力 与 接收能力 都是正常的。
两次握手 可以吗?不可以,如果只有两次握手,那么 服务器 不能知道> 客户端 的 接收能力 和 服务器 的 发送能力 是否正常。
四次握手 可以吗?可以,但是没必要。将 SYN 和 ACK 分开分别进行一次握手。
四次挥手
一次挥手:客户端发送 FIN 给服务器尝试断开连接
客户端 发送 FIN 给 服务器 ,表示自己数据已经传输完成,想跑路(断开连接)。
二次挥手:服务器返回 ACK 给客户端
服务器 已经知道 客户端 想要断开连接,返回 ACK 给 客户端。
此时 服务器 处于 CLOSE_WAIT 状态,即等待应用程序调用close()
。这个状态正常情况下存在时间较短。
三次挥手:服务器返回 FIN 给客户端
服务器 表示自己数据已经传输完成了,发送了 FIN 给 客户端,表示自己可以断开连接。
四次挥手:客户端返回 ACK 给服务器
客户端 收到 服务器 发来的 FIN,知道自己可以跑路了,然后返回给 服务器 有一个 ACK,表面自己已经知道可以跑路了的消息。于是便断开连接。
客户端 进入 TIME_WAIT 状态。谁主动断开连接,谁进入 TIME_WAIT 状态。
TIME_WAIT 存在的意义是防止最后一个 ACK 丢包。如果 一定时间 后对方没有重传 FIN,则销毁连接。
这个 一定时间 是 2MSL,MSL 表示网络中,两个主机之间传输数据的最大时间间隔,一来一回正好 2MSL。
为什么要四次挥手?三次挥手可以吗?
不行,挥手中少了任何一个步骤,总有一方都不能可靠的通知对方自己的数据已经传输完毕。
有人可能会问,第二次握手中 SYN 和 ACK 能合在一起作为一次握手,那么第二次挥手和第三次挥手的 FIN 和 ACK能否合在一起作为一次挥手呢?
答案是不确定,ACK 和 SYN 都是操作系统内核的行为。在收到 FIN 的第一时间就会回复 ACK。而 FIN 是应用程序的行为,执行到对应的
close();
,才会出发 FIN,是有时间差的,假如这个时间差很短,那么就会触发 “延时应答 + 捎带应答”,此时 ACK 和 FIN 就合成一个数据报发给客户端。(本质上还是 四次挥手)
当应用程序执行对应的close();
时间过长时,就会分开了。