【计算机网络】别再问我TCP的三次握手和四次挥手啦!

前言

我们都知道TCP是面向连接的,三次握手就是用来建立连接的,四次挥手(四次握手)就是用来断开连接的。下面就详细聊聊在面试过程中,经典必问网络问题TCP的三次握手、四次挥手的相关问题。

文章内容整理自网络!如有侵权联系我

介绍一下TCP三次握手?为什么不是两次?

1、为什么需要三次握手

在网络OSI 的七层模型中,物理层、数据链路层在物理层面上架设好了通信链路,网络层确定了通信双方的地址,那下一步就是在传输层建立逻辑层面上的通信连接,将从应用层获得的报文数据从源端发送给接受端。TCP的三次握手就是在发送数据前通过“三次握手”的方式建立起这个通信连接,建立这个连接的目的是让源端和目的端确认一下双方的发送报文能力和接收报文能力是正常的,简单说就是为了确认双方的接收与发送能力是否正常。

2、TCP报文首部

在介绍三次握手前先介绍一下TCP报文的首部,报文首部可以理解为报文的元数据,里面存放着与这次报文相关的其他信息,如下图,介绍一下跟三次握手相关的报文首部字段。

(1)序号(seq

表示对字节流的编号,占 4 个字节。 TCP 是面向字节流的,在一个 TCP 连接中传输的字节流中的每个字节都按照顺序编号。例如第一个字节的序号为 301,如果携带的数据长度为 100 字节,那么下一个报文段的序号应为 401。注意第一份报文段的序号是随机生成的,后面的报文段序号是根据上一个报文段序号及报文长度生成的。

(2)确认号(ack

表示期望收到对方下一个报文段的序号值,占 4 个字节。 TCP 的可靠性,是建立在「每一个数据报文都需要确认收到」的基础之上的。 就是说,通讯的任何一方在收到对方的一个报文之后,都要发送一个相对应的「确认报文」,来表达确认收到。那么,确认报文,就会包含确认号。

例如 B 正确收到 A 发送来的一个报文段,序号为 501,携带的数据长度为 200 字节,因此 B 期望下一个报文段的序号为 701,B 发送给 A 的确认报文段中确认号就为 701。

(3)控制位SYN

控制位的一种同步位,用于建立连接,该位设为 1,表示希望建立连接,并对第一份报文的序号进行随机初始化。

(4)控制位ACK

控制位的一种,确认应答的字段有效,TCP规定除了最初建立连接时的 SYN 包以外该位必须设为 1

(5)控制位FIN

控制位的一种,当FIN=1,表明此报文的发送方的数据已经发送完毕,要求关闭连接。

3、三次握手具体过程

刚开始客户端处于 closed 的状态,服务端处于 listen 状态。然后

  • 第一次握手

    客户端将SYN置为1,表示希望与服务端建立连接;序号seq初始化为任意值J,并将该数据包发送给服务端,客户端进入SYN_SENT状态,等待服务端确认。

  • 第二次握手

    第二次握手包括服务端确认客户端发来的报文服务端向客户端发送报文两个过程。

    服务端检查接收到的报文发现SYN为1,知道了客户端想建立连接;服务端将ACK置为1,表示收到了客户端建立连接的请求;服务端将SYN置为1,表示服务端也希望与客户端建立连接;服务端将序号seq初始化为K;服务端将确认号ack置为J+1,然后向客户端发送报文。

  • 第三次握手

    第三次握手包括客户端确认服务端发来的报文客户端向服务端发送报文服务端确认客户端发来的报文三个过程。

    客户端收到报文后,检查确认号ack是否为J+1,ACK是否为1,如果正确则将标志位ACK置为1,确认号ack=K+1,并将该数据包发送给服务端,服务端检查确认号ack是否为K+1,ACK是否为1,如果正确则连接建立成功,客户端和服务端进入ESTABLISHED状态,完成三次握手,随后客户端与服务端之间可以开始传输数据了。

4、为什么两次却不可以?

第一次握手:客户端发送网络包,服务端收到。这样服务端就能得出结论:客户端的发送能力、服务端的接收能力是正常的。

第二次握手:服务端发包,客户端收到了。这样客户端就能得出结论:服务端的接收、发送能力,客户端的接收、发送能力是正常的。不过此时服务器并不能确认客户端的接收能力是否正常

第三次握手:客户端发包,服务端收到了。这样服务端就能得出结论:客户端的接收、发送能力正常,服务器自己的发送、接收能力也正常。

因此,需要三次握手才能确认双方的接收与发送能力是否正常。

5、什么是半连接队列?

服务器第一次收到客户端的 SYN 之后,就会处于 SYN_RCVD 状态,此时双方还没有完全建立其连接,服务器会把此种状态下请求连接放在一个队列里,我们把这种队列称之为半连接队列

当然还有一个全连接队列,就是已经完成三次握手,建立起连接的就会放在全连接队列中。如果队列满了就有可能会出现丢包现象。

这里在补充一点关于SYN-ACK 重传次数的问题: 服务器发送完SYN-ACK包,如果未收到客户确认包,服务器进行首次重传,等待一段时间仍未收到客户确认包,进行第二次重传。如果重传次数超过系统规定的最大重传次数,系统将该连接信息从半连接队列中删除。 注意,每次重传等待的时间不一定相同,一般会是指数增长,例如间隔时间为 1s,2s,4s,8s......

介绍一下TCP四次挥手?为什么不是三次、五次?

1、为什么需要四次挥手?

建立一个连接需要三次握手,而终止一个连接要经过四次挥手,即客户端和服务端总共要收发4个包才能确定断开连接。这由TCP的半关闭(half-close)造成的。所谓的半关闭,其实就是TCP提供了连接的一端在结束它的发送后还能接收来自另一端数据的能力。

2、四次挥手的具体过程

TCP 的连接拆除需要发送四个包,因此称为四次挥手(Four-way handshake),客户端或服务器均可主动发起挥手动作。刚开始双方都处于 ESTABLISHED 状态,假如是客户端先主动发起关闭请求。四次挥手的过程如下:

  • 第一次挥手

    客户端向服务端发送报文,报文首部包括FIN=1,这个控制位代表客户端想要断开连接;序列号seq=u,这时客户端进入FIN-WAIT-1(终止等待1)状态,停止发送数据,并等待服务端的确认。

  • 第二次挥手

    服务端收到客户端的报文后发出确认报文,控制位ACK=1;确认号ack=u+1;序列号seq=v;然后服务端就进入CLOSE-WAIT(关闭等待)状态。TCP服务端会告知上层的应用进程来自客户端的连接即将关闭,让应用程序做好相应的准备。此时客户端已经没有数据向服务端发送了,但服务端向客户端发送数据,客户端依然能接收。

  • 第三次挥手

    客户端收到服务器确认报文后,进入FIN-WAIT-2状态。此时服务器再次发送报文,报文首部控制位FIN=1,表示服务端向客户端发送断开连接请求;确认标志ACK=1;确认序号ack=u+1;序号seq=w,然后服务器进入LAST-ACK(最后确认态),等待客户端确认。

  • 第四次挥手

    客户端收到了服务端的断开连接的报文后,必须发出确认报文,标志位ACK=1;确认号ack=w+1;序号seq=u+1;之后客户端就进入了TIME-WAIT(时间等待)状态。注意此时客户端的TCP连接还没有释放,必须经过2*MSL(最长报文段寿命)的时间后,客户端才进入CLOSED状态关闭连接而服务端只要收到了客户端发送的确认报文后就会进入CLOSED状态关闭服务端连接

当客户端和服务端都进入了CLOSED状态后,客户端和服务端之间的连接才完全断开。

3、为什么会有TIME_WAIT状态?

上面介绍第四次挥手的过程中,客户端在发送完给服务端的回执报文后没有立刻进入CLOSED状态,而是进入TIME-WAIT状态,然后等待2*MSL(最长报文段寿命)的时间后才进入CLOSED状态,这是为什么?原因有以下两点:

  • 客户端发送给服务端回执后,有可能这个回执报文在传输途中丢失等原因,服务端并没有收到,此时服务端会再次向客户端发送FIN=1的断开请求报文,如果客户端没有等待2*MSL时间而直接进入了CLOSED状态,客户端就会收不到服务端再次发送的断开连接的请求报文,导致服务端无法进入CLOSED状态;

  • 等待一段时间是为了让本连接持续时间内所产生的所有报文都从网络中消失,使得下一个新的连接不会出现旧的连接请求报文。

注:MSL是Maximum Segment Lifetime英文的缩写,中文可以译为“报文最大生存时间”,他是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。

4、 为什么是四次挥手而不是三次或者五次?

第二次挥手和第三次挥手都是服务端向客户端发送报文,第二次挥手是服务端收到了客户端的断开请求,通知客户端俺收到了,此时客户端没有数据向服务端发送了,但不代表服务端也没有数据向客户端发送,因为服务端要把剩余还没有发送的报文发送完毕再断开连接;第三次挥手是服务端数据全部发送完毕,向客户端发送断开请求报文(FIN=1)。

如果是三次挥手,即把服务端向客户端发送报文的第二次挥手和第三次挥手合为一次,会造成服务端发送了回执后立刻又发送断开请求,造成服务端有数据没有全部发送至客户端,因此必须将第二次挥手和第三次挥手分开;五次挥手则完全没必要,多此一举。

5、在四次挥手中,为什么客户端进入TIME_WAIT状态等待2*MSL时间,而不是直接进入CLOSED状态?

客户端在发送完给服务端的回执报文后没有立刻进入CLOSED状态,而是进入TIME-WAIT状态,然后等待2*MSL(最长报文段寿命)的时间后才进入CLOSED状态,这是为什么?原因有以下两点:

  • 客户端发送给服务端回执后,有可能这个回执报文在传输途中丢失等原因,服务端并没有收到,此时服务端会再次向客户端发送FIN=1的断开请求报文,如果客户端没有等待2*MSL时间而直接进入了CLOSED状态,客户端就会收不到服务端再次发送的断开连接的请求报文,导致服务端无法进入CLOSED状态;

  • 等待一段时间是为了让本连接持续时间内所产生的所有报文都从网络中消失,使得下一个新的连接不会出现旧的连接请求报文。

注:MSL是Maximum Segment Lifetime英文的缩写,中文可以译为“报文最大生存时间”,他是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。

为什么建立连接是三次握手,关闭连接确是四次挥手呢?

建立连接的时候, 服务器在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。 而关闭连接时,服务器收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,而自己也未必全部数据都发送给对方了,所以己方可以立即关闭,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,己方ACK和FIN一般都会分开发送,从而导致多了一次。

微信关注

编程那点事儿

本站为非盈利性站点,所有资源、文章等仅供学习参考,并不贩卖软件且不存在任何商业目的及用途,如果您访问和下载某文件,表示您同意只将此文件用于参考、学习而非其他用途。
本站所发布的一切软件资源、文章内容、页面内容可能整理来自于互联网,在此郑重声明本站仅限用于学习和研究目的;并告知用户不得将上述内容用于商业或者非法用途,否则一切后果请用户自负。
如果本站相关内容有侵犯到您的合法权益,请仔细阅读本站公布的投诉指引页相关内容联系我,依法依规进行处理!
作者:理想
链接:https://www.imyjs.cn/archives/930
THE END
二维码
【计算机网络】别再问我TCP的三次握手和四次挥手啦!
前言 我们都知道TCP是面向连接的,三次握手就是用来……
<<上一篇
下一篇>>
文章目录
关闭
目 录