TCP的三次握手与四次挥手

一、概述

本篇博客是经由他人书籍以及博客总结得出的知识点,属于笔者的学习笔记,它的结构如下:

  • TCP 报文首部
  • TCP 的三次握手
  • TCP 的四次挥手

二、TCP 报文首部

TCP 报文首部如下图所示:

TCP的三次握手与四次挥手

  • 源端口:表示发送端端口,字段长为16位,即2个字节。
  • 目的端口:表示接收端端口,字段长为16位,即2个字节。
  • seq(序号):表示发送数据的位置,字段长为32位,即4个字节。TCP连接中传送的字节流中的每个字节都按顺序编号。例如一段报文的序号字段值为101,携带的数据共有100个字节,那么下一个报文段的数据序号应当从201开始。注意***不会从0或1开始,而是在建立连接时由计算机生成的一个随机数作为其初始值
  • ack(确认号):表示期望收到对方下一个报文的第一个数据字节的序号,字段长为32位,即4个字节。例如,B收到了A发送而来的报文,其序号字段值为101,数据长度为100个字节,这表明B正确收到了A发送的到序号200为止的数据,因此B期望收到的A下一个数据序号字段值为201,所以B在发送给A的确认报文段中把确认号置为201。
  • 控制位:长度为6位,从左到右以此为 URG、ACK、PSH、RST、SYN 和 FIN。当对应值为 1 时,表示其有具体含义:
标志位 含义
URG 当URG=1,表明紧急指针字段有效。告诉系统此报文段中有紧急数据
ACK 仅当ACK=1时,确认号字段才有效。TCP规定,在连接建立后所有报文的传输都必须把ACK置1
PSH 当PSH =1,提示接收端应用程序立即从TCP缓冲区把数据读走
RST 当RST=1,表明TCP连接中出现严重差错,必须释放连接,然后再重新建立连接
SYN 在连接建立时用来同步序号。当SYN=1,ACK=0,表明是连接请求报文,若同意连接,则响应报文中应该使SYN=1,ACK=1
FIN 当FIN=1,表明此报文的发送方的数据已经发送完毕,并且要求释放
  • 窗口:表示接收方需要有多大的空间来接收本报文,字段长为16位,即2个字节。
  • 校验和:校验首部和数据这两部分,接收校验不通过,则认为数据有问题。字段长为16位,即2个字节。
  • 紧急指针:只有在URG为1时有效,表示本报文段中的紧急数据的字节数,字段长为16位,即2个字节。
  • 选项:长度可变,定义一些其他的可选的参数。

三、TCP 连接的建立(三次握手)

TCP 三次握手要达成的目的:

  • 使连接双方做好发送数据的准备工作(双方都知道彼此已准备好)。
  • 使连接双方就初始***进行协商,这个***在握手过程中被发送和确认。

示意图如下所示:

TCP的三次握手与四次挥手

客户端:主动打开连接的即为客户端。
服务端:被动打开连接的即为服务端。

在握手之前,TCP 服务器进程先创建传输控制块 TCB,时刻准备接受客户进程的连接请求,此时服务器就进入了 LISTEN(监听)状态。

第一次握手

客户端首先传输控制块 TCB,然后向服务器发出连接请求报文,其中 SYN=1,seq=x(x 为计算机生成的一个随机数)。此时客户端进入 SYN-SENT 状态。TCP规定,SYN报文段(SYN=1的报文段)不能携带数据,但需要消耗掉一个序号

第二次握手

在服务端收到连接请求报文后,如果服务器同意连接,就会向客户端发送确认报文。确认报文中 SYN=1,ACK=1,(确认号)ack=x+1,(序号)seq=y,其中 y 为服务端的初始化***。在发送该报文之后服务端进入 SYN-RCVD 状态。这个报文也不能携带数据,但是同样要消耗一个序号

第三次握手

在客户端收到服务器发送来的确认报文之后,还需要向服务器发出确认。确认报文的 ACK=1,ack=y+1,seq=x+1。此时,TCP 连接建立,客户端进入 ESTABLISHED 状态。TCP 规定,ACK 报文段可以携带数据,但是如果不携带数据则不消耗序号。

而在服务端收到客户端的确认之后也会进入 ESTABLISHED 状态,此时客户端和服务端之间就可以相互传输数据了。三次握手完成!

思考1:为何要进行第三次握手,两次不可以吗?

假设客户端和服务端的连接只需要两次握手,现考虑如下特殊情况:

客户端请求建立连接,向服务器发送请求连接报文。服务器在收到请求报文之后,就会向客户端发送一个确认报文,此时服务端认为连接已经建立。但在传输的过程中,该数据丢失,那么客户端此时就会认为自己尚未与服务端建立连接,所以就会进行重传。而如果服务端发送的数据一直丢失而客户端一直在进行重传,那么服务器就会产生多个无效连接,占用资源,这个时候服务器可能会挂掉。

而在加入了第三次握手之后,服务端在第二次接收到客户端发送的报文之后才会认为连接已经建立,再出现上述情况的时候,由于三次握手的缘故,此时服务器就不会认为连接已经建立,就会放弃此次连接,和客户端重新进行连接确认。

思考2:如果已经建立了连接,但是客户端突然出现故障了怎么办?

如果客户端出现故障,显然服务器需要在适当的时候关闭连接,以免资源浪费。TCP
设置有一个保活计时器,通常时间为2小时,每次服务端接收到客户端的报文时都会重置这个计时器。如果超过了保活时间之后服务端还未收到客户端的报文,那么服务端就会每隔75s发送一个探测报文,若一连发送了10个探测报文之后仍然没反应,服务端就会认为客户端发生了故障,就会关闭连接。

四、TCP 连接的释放(四次挥手)

TCP 的四次挥手示意图如下:

TCP的三次握手与四次挥手

第一次挥手

客户端发出释放连接报文,并且停止发送数据。释放连接报文首部 FIN=1,seq=u(等于前面已经传送过来的数据的最后一个字节的序号加1)。此时客户端由 ESTABLISHED 状态进入到 FIN-WAIT-1 状态。TCP 规定,FIN 报文段即使不携带数据,也要消耗一个序号。

第二次挥手

服务器收到客户端发送的释放连接报文后,服务器向客户端发送一个确认报文,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 状态,该状态持续时间为 2MSL,该时间过去之后客户端就会进入到 CLOSED 状态。

而服务器在接收到客户端发来的确认报文之后,就直接进入到了 CLOSED 状态。

思考1:为何释放连接需要四次挥手而建立连接的时候只需要三次?

因为释放连接需要经过双方的同意。挥手产生的原因是因为客户端没有数据需要发送给服务端了,所以客户端想要和服务端断开连接,所以头两次挥手断开的是客户端向服务端通信的方向。
客户端没有数据发送给服务端不代表服务端没有数据要发送给客户端,所以此时服务端向客户端发送数据的通信方向仍然保持着,等到服务端也没有数据需要发送之后,服务端才会向客户端发送释放连接报文,关闭彼此之间的连接,这就是后两次挥手所做的。

思考2:在第四次挥手的时候客户端为何要等待 2MSL?

MSL(Maximum Segment Lifetime),即最大报文生存时间,是任何报文在网络上的存在的最长时间,超过这个时间报文将被丢弃。等待 2MSL 的时间是为了防止服务器没有收到第四次挥手的确认报文。

如果服务器没有收到第四次挥手的确认报文,那么在超过 MSL 的时间之后,它就会重新向客户端发送释放连接报文,也就是重新进行第三次挥手,在客户端收到重新发送来的释放连接报文之后可以再次向服务端发送确认报文(第四次挥手)。

需要注意的是在客户端重新发送确认报文之后,客户端会再一次进入到 TIME-WAIT 状态。

参考

本文参考自以下博客:

TCP的三次握手与四次挥手(详解+动图)

TCP三次握手及四次挥手详解及常见面试题

TCP的三次握手与四次挥手理解及面试题(很全面)


希望这篇文章对您有所帮助~如果有任何问题可以在下方评论区评论或者直接私信笔者。