计算机网络:三次握手四次挥手原因


TCP数据在传输之前先要建立连接,建立连接需要进行3次通信,这三次通信被称为“三次握手”,在数据传输完成后断开连接时要进行四次通信,被称为“四次挥手”。

一、TCP中常用的控制位和数据结构

控制位:

控制位 含义
ACK 为1时表示确认好有效,为0是表示报文中不包含确认信息,忽略确认号字段
SYN 同步序号,为1是表示连接请求,用于建立连接和使顺序序号同步
FIN 用于释放连接,为1时表示发送方已经没有什么数据要发送,即关闭本方数据流

数据结构:

数据结构 含义
seq(32位) 顺序号,标识从TCP源端向TCP目的端发送的数据字节流,表示这个报文段中第一个数据字节的顺序号
ack(32位) 确认号,存储发送确认的一端所期望收到的下一个顺序号。确认号是上一个已成功收到的数据字节流顺序号加1

二、三次握手

1、三次握手过程

(1)客户端发送SYN(seq=x)报文给服务器,进入SYN_SEND状态。
(2)服务器端收到SYN报文,回应一个SYN(seq=y)和ACK(ack=x+1)报文,进入SYN_RECV状态。
(3)客户端收到服务器端的SYN报文,回应一个ACK(ack=y+1)报文,进入Established状态。
以上三次握手之后,TCP的客户端和服务器端就已经建立好连接了,可以开始传输数据了。
三次握手

2、为什么不是两次握手或四次握手

握手的目的是为了序列号seq一致,而上述两个握手要么是做不到序列号一致,要么是多此一举。

(1)两次握手过程:

粗略描述如下:
(1)客户端发送请求连接SYN报文
(2)服务器端收到SYN,返回一个请求连接SYN报文和确定连接ACK报文
由此可知,经过上面两次握手,只有客户端知道了序列号,但是服务器端不知道,不能达到序列号一致,就不可以保证通信的可靠性。

(2)四次握手过程:

粗略描述如下:
(1)客户端发送请求连接SYN报文
(2)服务器端收到SYN,并记录到本地,命名为服务器的seq
(3)服务器端发送SYN报文和ACK报文给客户端
(4)客户端收到服务端发送的SYN和ACK,再发送一个ACK给服务器端
由此可知,第(2)(3)步其实可以合并起来作为三次握手的第二步,没有必要四次握手。

3、总结

由于TCP传输是双向的,每个方向的通道建立都需要一次SYN和ACK,所以建立两个方向最多需要两次(SYN+ACK),即四次挥手,但是其中第二次和第三次握手可以合并,且合并后延迟更低,所以使用三次握手。而两次握手只能建立一个单方向的通道,不可以使通信双方都通信。

三、四次挥手

由于TCP在建立连接时,数据是可以在两个方向上独立传递的,所以在进行关闭时要单独对两个方向进行关闭。

1、四次挥手过程

(1)客户端应用进程调用断开连接请求,向服务端发送一个终止标志位FIN=1,seq=u的消息,表示客户端在关闭链路前要发的数据都已经发完,可以准备关闭链路操作,即可以关闭数据输出。此时客户端处于FIN-WAIT-1状态。
(2)服务器在收到这个FIN消息后返回一个ACK=1,ack=u+1,seq=v的消息给客户端,表示收到客户端断开链路的请求操作。此时服务器处于CLOSE-WAIT状态。客户端在收到消息后处于FIN-WAIT-2状态。
(3)服务器端在关闭链路前需要将发送给客户端的消息发送个客户端,等待该数据发送完毕后,发送一个终止标志位FIN=1,ACK=1,seq=w,ack=u+1的消息给客户端,表示服务器端在关闭链路前要发的数据都已经发完,可以准备关闭链路操作,此时服务器端处于LAST-ACK状态。
(4)客户端在收到这个最终消息后,发送一个ACK=1,seq=u+1,ack=w+1的消息给服务器端,表示收到服务器端的结束信号并准备断开服务器端到客户端的链路。此时客户端处于TIM-WAIT状态,TCP连接还没有释放,等再经过等待计时器(2MSL)设置的超时时间后,客户端进入CLOSED状态。
四次挥手

2、为什么不能二次挥手

这里我引用一下再b站评论里看到的神评,up主“泪眼问花灬花不语”这样描述道:
“四次挥手为什么是四次,也就是说第二次挥手的时候为什么不是FIN+ACK一起发送,根本原因没讲出来。其实发送FIN的意思是终止这一方向的数据传输,而接收到FIN的意思是这一方向上已经没有数据可以接收了,但仍可以发送数据。第一次挥手:客户端向服务端发送FIN,客户端对服务端说:我已经没有数据要发送了,想结束连接,虽然你已经没有数据可接收了,但我知道数据发送是以数据流的形式传输的,所以如果你还有数据没发送完可以不用着急关闭,我等你。第二次挥手:服务端向客户端发送ACK。服务端对客户端说:老弟呀,你的请求我收到了哈,但我不能马上断开哈,还真让你说对了,我还真有点东西没发送完,但我不能一声不吭让你默默的等啊,我先给你发送个ACK吧。第三次挥手:服务端向客户端发送FIN。服务端对客户端说:艾玛终于搞完了,我这边也没数据要发送了,那我就把FIN给你发过去了哈,我也同意断开了。注意此时服务端并没有断开哦,它还在等最终确认。第四次挥手:客户端向服务端发送ACK。客户端对服务端说:你发的FIN我收到了,既然你那边也没东西要发送了,那咱就断开吧。此时服务端想:这货最后的ACK怎么还不到啊,我得拿到最后的ACK才能断开啊,迟迟不给我ACK的话是不是他没收到我的FIN啊,再不给我ACK我就再给他发一次FIN,反正我拿不到ACK我就一直给你发FIN,哼!刚说完服务端就拿到了ACK,开开心心的断开了连接。这时客户端想:这网络会不会靠不住啊,对面到底收没收到我的ACK啊,万一我的ACK丢包了咋办,要不我再等等吧,就等2MSL(这个时间是数据包往返客户端和服务端一次的最大时长)这么长时间,反正他如果没收到我的ACK还会向我发送FIN的。2MSL的时间过去了。客户端:咦,没有再次收到他的FIN,说明这货已经拿到了我的ACK断开了啊,那我也断开吧!至此,二者彻底断开了连接!”

Guess you like

Origin blog.csdn.net/UncleBlain/article/details/108917028