第三次握手为什么没有序列号_教你用不尬的方式去理解TCP三次握手和四次挥手...

第三次握手为什么没有序列号_教你用不尬的方式去理解TCP三次握手和四次挥手..._第1张图片

写在前面

关于TCP连接之前建立三次握手和收发数据完毕之后四次挥手的知识点看过很多次每次记完就忘,原因还是因为自己完全靠死记硬背根本没有从理解核心问题本身。而看完网上很多文章,不得不说,很多的“强行解释”让我觉得尬到无地自容。所以,写一篇文章来重新审视一下这个问题。文章不长,很快看完。

TCP连接三次握手

还是这张让人深恶痛绝的图

第三次握手为什么没有序列号_教你用不尬的方式去理解TCP三次握手和四次挥手..._第2张图片

握手过程:

第一次握手:

客户端发送syn包(Seq=x)到服务器,并进入SYN_SEND状态,等待服务器确认;

第二次握手:

服务器收到syn包,必须确认客户的SYN(ack=x+1),同时自己也发送一个SYN包(Seq=y),即SYN+ACK包,此时服务器进入SYN_RECV状态;

第三次握手:

客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=y+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。

下面进入正题:

Q1:建立三次握手的目的是什么?

答:同时确认通信双方的收发功能都没有问题。说人话,小明和小红沟通,需要同时知道,自己和对方的耳朵和声带都没有问题。

让我们用表格的方式重新来还原整个握手过程:

第一次握手:
客户端发送syn包(Seq=x)到服务器,并进入SYN_SEND状态,等待服务器确认;

7c176dde0749a7d8cd0911bcc2f7a3af.png

横坐标代表客户端和服务端,纵坐标代表分别从客户端(client)和服务端(server)的角度看,自己和对方的收发情况。

描述:第一次握手,server可以收到client 的消息,也就是从server的角度看,client的发送能力没问题,并且自己(server)能够接受到,说明自己的接收能力没问题。

第二次握手:
服务器收到syn包,必须确认客户的SYN(ack=x+1),同时自己也发送一个SYN包(Seq=y),即SYN+ACK包,此时服务器进入SYN_RECV状态;

99ec97556478fb74dc16a0d3df09667d.png

描述:

从client的角度看,

  • 自己能收到server发的消息,所以自己(client)的接收能力和server的发送能力过关
  • server发的确认消息(ack=x+1),和自己之前发的(seq=x)是相关联的,所以此前server肯定接收到了消息,因此server的接收能力可行,并且自己(client)的发送能力过关。
第三次握手:
客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=y+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。

35df68d53254e643fab34ff80eed27bf.png

描述:

从服务端看:

  • client 发送了ack=y+1和之前第二次握手时server发送的seq=y 是相关联的,可以判断出client的接收功能没问题,不然不可能发出ack=y+1,然后自己(server)之前的seq=y成功发出了,说明server的发送能力没问题。
Q2:为什么是三次握手?

答:综上,可以判断出,进行握手的核心问题是为了解决,让客户端和服务端分别从他们自己的角度认识到自己和对方的收发能力没有问题,而这个过程,至少需要三次握手。当然,也可以是四次握手,五次握手。只是,从效率来看,三次是最少的。

TCP四次挥手

四次挥手也是同样的道理,先上图:

第三次握手为什么没有序列号_教你用不尬的方式去理解TCP三次握手和四次挥手..._第3张图片

第一次挥手:

客户端发送一个FIN,用来关闭客户端到服务器的数据传送,也就是客户端告诉服务器:我已经不 会再给你发数据了(当然,在fin包之前发送出去的数据,如果没有收到对应的ack确认报文,客户端依然会重发这些数据),但是,此时客户端还可 以接受数据。 FIN=1,其序列号为seq=u(等于前面已经传送过来的数据的最后一个字节的序号加1),此时,客户端进入FIN-WAIT-1(终止等待1)状态。 TCP规定,FIN报文段即使不携带数据,也要消耗一个序号。

第二次挥手:

服务器收到FIN包后,发送一个ACK给对方并且带上自己的序列号seq,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号)。此时,服务端就进入了CLOSE-WAIT(关闭等待)状态。TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间。

此时,客户端就进入FIN-WAIT-2(终止等待2)状态,等待服务器发送连接释放报文(在这之前还需要接受服务器发送的最后的数据)。

第三次挥手:

服务器发送一个FIN,用来关闭服务器到客户端的数据传送,也就是告诉客户端,我的数据也发送完了,不会再给你发数据了。由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为seq=w,此时,服务器就进入了LAST-ACK(最后确认)状态,等待客户端的确认。

第四次挥手:

主动关闭方收到FIN后,发送一个ACK给被动关闭方,确认序号为收到序号+1,此时,客户端就进入了TIME-WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过2∗MSL(最长报文段寿命)的时间后,当客户端撤销相应的TCB后,才进入CLOSED状态。

服务器只要收到了客户端发出的确认,立即进入CLOSED状态。同样,撤销TCB后,就结束了这次的TCP连接。可以看到,服务器结束TCP连接的时间要比客户端早一些。

至此,完成四次挥手。

Q3:四次挥手的目的是什么?

答:为了关闭连接,那么再准确点应该是什么?是为了分别从客户端和服务端都确保自己和对方都不再发送数据。

于是,问题列出来,每一步在做什么就很清晰了。还是用表格说明。

第一次挥手:
客户端发送一个FIN,用来关闭客户端到服务器的数据传送,也就是客户端告诉服务器:我已经不 会再给你发数据了(当然,在fin包之前发送出去的数据,如果没有收到对应的ack确认报文,客户端依然会重发这些数据),但是,此时客户端还可 以接受数据。 FIN=1,其序列号为seq=u(等于前面已经传送过来的数据的最后一个字节的序号加1),此时,客户端进入FIN-WAIT-1(终止等待1)状态。 TCP规定,FIN报文段即使不携带数据,也要消耗一个序号。

2a82195a2f33fb284134d5674948a9e1.png

描述:

从服务端的角度看,

首先,server收到client请求已经发送完毕,之后就不再发送的消息。

第二次挥手:
服务器收到FIN包后,发送一个ACK给对方并且带上自己的序列号seq,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号)。此时,服务端就进入了CLOSE-WAIT(关闭等待)状态。TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间。

d1d94209dace12f861fd36ceb9b6bdfe.png

描述:

从客户端来看,

收到server的确认序号seq+1 ,说明自己终止发送的消息生效。

第三次挥手:
服务器发送一个FIN,用来关闭服务器到客户端的数据传送,也就是告诉客户端,我的数据也发送完了,不会再给你发数据了。由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为seq=w,此时,服务器就进入了LAST-ACK(最后确认)状态,等待客户端的确认。

e8b8ee9d668c07e18eba0ba9f2dc993a.png

描述:

从客户端的角度看,

client收到server发送数据完毕的序列号w,可以确定server将不再发送。

第四次挥手:
主动关闭方收到FIN后,发送一个ACK给被动关闭方,确认序号为收到序号+1,此时,客户端就进入了TIME-WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过2∗MSL(最长报文段寿命)的时间后,当客户端撤销相应的TCB后,才进入CLOSED状态。

668ab956bd668eaaa6f7e53c013839cf.png

描述:

从服务端的角度看,server收到client的确认序号,说明自己(server)自己不再发送的消息生效。

Q4:为什么连接时握手是3次,而挥手需要4次?

答:假如3次挥手就能解决,第一个想到的合并是肯定第二步和第三步。问题是,第二步是客户端向服务端说明自己的请求消息已经完毕,而第三步的任务是服务端的响应数据已经完毕,这两者显然不能合并阿,服务端的请求处理是需要时间的,中间必然会存在时间间隔,四次就是挥手断开连接的最优解。

参考:

史上最详细的经典面试题 从输入URL到看到页面发生了什么?​juejin.im

你可能感兴趣的:(第三次握手为什么没有序列号)