TCP连接的三次握手和四次挥手详解

TCP(Transmission Control Protocol,传输控制协议)是一种面向连接的、可靠的、基于字节流的通信协议,数据在传输前要建立连接,传输完毕后还要断开连接,客户端在收发数据前要使用 connect() 函数和服务器建立连接。建立连接的目的是保证IP地址、端口、物理链路等正确无误,为数据的传输开辟通道。

在了解三次握手和四次挥手的操作前需要了解下Tcp数据报的结构:
在这里插入图片描述
重点关注的是数据序号、确认序号、以及标志位(U、A、P、R、S、F);

数据序号:Seq(Sequence Number)序号占32位,用来标识从计算机A发送到计算机B的数据包的序号,计算机发送数据时对此进行标记。
确认序号:Ack(Acknowledge Number)确认号占32位,客户端和服务器端都可以发送,Ack = Seq + 1。
标志位:每个标志位占用1Bit,共有6个,分别为 URG、ACK、PSH、RST、SYN、FIN,具体含义如下:

  • URG:紧急指针(urgent pointer)有效。
  • ACK:确认序号有效。
  • PSH:接收方应该尽快将这个报文交给应用层。
  • RST:重置连接。
  • SYN:建立一个新连接。
  • FIN:断开一个连接。

客户端和服务端连接过程:
在这里插入图片描述

三次握手

在这里插入图片描述
客户端调用 socket() 函数创建套接字后,因为没有建立连接,所以套接字处于CLOSED状态;服务器端调用 listen() 函数后,套接字进入LISTEN状态,开始监听客户端请求
这时客户端发起请求:
  1) 当客户端调用 connect() 函数后,TCP协议会组建一个数据包,并设置 SYN 标志位,表示该数据包是用来建立同步连接的。同时生成一个随机数字假设为1000,填充“序号(Seq)”字段,表示该数据包的序号。完成这些工作,开始向服务器端发送数据包,客户端就进入了SYN-SEND状态。
  2) 服务器端收到数据包,检测到已经设置了 SYN 标志位,就知道这是客户端发来的建立连接的“请求包”。服务器端也会组建一个数据包,并设置 SYN 和 ACK 标志位,SYN 表示该数据包用来建立连接,ACK 用来确认收到了刚才客户端发送的数据包
  服务器生成一个随机数假设为 2000,填充“序号(Seq)”字段。2000 和客户端数据包没有关系。
  服务器将客户端数据包序号(1000)加1,得到1001,并用这个数字填充“确认号(Ack)”字段。
  服务器将数据包发出,进入SYN-RECV状态
  3) 客户端收到数据包,检测到已经设置了 SYN 和 ACK 标志位,就知道这是服务器发来的“确认包”。客户端会检测“确认号(Ack)”字段,看它的值是否为 1000+1,如果是就说明连接建立成功。
接下来,客户端会继续组建数据包,并设置 ACK 标志位,表示客户端正确接收了服务器发来的“确认包”。同时,将刚才服务器发来的数据包序号(2000)加1,得到 2001,并用这个数字来填充“确认号(Ack)”字段。
  客户端将数据包发出,进入ESTABLISED状态,表示连接已经成功建立。
  4) 服务器端收到数据包,检测到已经设置了 ACK 标志位,就知道这是客户端发来的“确认包”。服务器会检测“确认号(Ack)”字段,看它的值是否为 2000+1,如果是就说明连接建立成功,服务器进入ESTABLISED状态。
  至此,客户端和服务器都进入了ESTABLISED状态,连接建立成功,接下来就可以收发数据了。

四次挥手

在这里插入图片描述
建立连接后,客户端和服务器都处于ESTABLISED状态。这时,客户端发起断开连接的请求:

  • 客户端调用 close() 函数后,向服务器发送 FIN 数据包,进入FIN_WAIT_1状态。FIN 是 Finish 的缩写,表示完成任务需要断开连接。

  • 服务器收到数据包后,检测到设置了 FIN 标志位,知道要断开连接,于是向客户端发送“确认包”,进入CLOSE_WAIT状态。

    注意:服务器收到请求后并不是立即断开连接,而是先向客户端发送“确认包”,告诉它我知道了,我需要准备一下才能断开连接。

  • 客户端收到“确认包”后进入FIN_WAIT_2状态,等待服务器准备完毕后再次发送数据包。

  • 等待片刻后,服务器准备完毕,可以断开连接,于是再主动向客户端发送 FIN 包,告诉它我准备好了,断开连接吧。然后进入LAST_ACK状态。

  • 客户端收到服务器的 FIN 包后,再向服务器发送 ACK 包,告诉它你断开连接吧。然后进入TIME_WAIT状态。

    注意:这时候为什么客户端处于TIME_WAIT状态而不是直接进入CLOSED状态;是因为客户端必须保证数据能够正确到达目标机器,不能丢失或出错,而网络是不稳定的,有可能会因为网络问题导致服务器收不到;如果服务器没有收到数据;就会再次发送 FIN 包,如果这时客户端完全关闭了连接,那么服务器无论如何也收不到ACK包了;那客户端又是什么时候进入CLOSED状态呢?首先数据包在网络中是有生存时间的,超过这个时间还未到达目标主机就会被丢弃,并通知源主机。这称为报文最大生存时间(MSL,Maximum Segment Lifetime)。
    所以客户端会等待 2MSL 如果没有收到服务端发送的Fin包,就表示服务端收到消息了;此时客户端才会进入 CLOSED 状态;为什么是等到2MSL则是因为ACK 包到达服务器需要 MSL 时间,服务器重传 FIN 包也需要 MSL 时间;刚好是一个数据来回;

  • 服务器收到客户端的 ACK 包后,就断开连接,关闭套接字,进入CLOSED状态

猜你喜欢

转载自blog.csdn.net/wzb_wzt/article/details/107820064