F_JustWei's Studio.

TCP的三次握手和四次挥手

字数统计: 2.7k阅读时长: 9 min
2021/04/05 Share

TCP的三次握手和四次挥手

1、TCP简介

  1. TCP(Transmission Control Protocol,传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。数据在传输前要建立连接,传输完毕后还要断开连接。
    • 面向连接:一定是一对一才能连接,不能像 UDP 协议可以一个主机同时向多个主机发送消息,也就是一对多是无法做到的。
    • 可靠的:无论的网络链路中出现了怎样的链路变化,TCP 都可以保证一个报文一定能够到达接收端。
    • 字节流:消息是没有边界的,所以无论我们消息有多大都可以进行传输。并且消息是有序的,当前一个消息没有收到的时候,即使它先收到了后面的字节,那么也不能扔给应用层去处理,同时对重复的报文会自动丢弃。
  2. 客户端在收发数据前要使用 connect() 函数和服务器建立连接。建立连接的目的是保证IP地址、端口、物理链路等正确无误,为数据的传输开辟通道。
  3. TCP建立连接时要传输三个数据包,俗称三次握手(Three-way Handshaking)。

2、TCP数据报结构

TCP 头格式

  1. 序列号:Seq(Sequence Number)序列号占32位,用来标识从计算机A发送到计算机B的数据包的序列号,计算机发送数据时对此进行标记。
  2. 确认应答号:Ack(Acknowledge Number)确认应答号占32位,客户端和服务器端都可以发送,Ack = Seq + 1。
  3. 标志位:每个标志位占用1Bit,共有6个,分别为 URG、ACK、PSH、RST、SYN、FIN,具体含义如下:
    • URG:紧急指针(urgent pointer)有效。
    • ACK:确认应答号有效。
    • PSH:接收方应该尽快将这个报文交给应用层。
    • RST:重置连接。
    • SYN:建立一个新连接。
    • FIN:断开一个连接。

3、TCP的三次握手

TCP 是面向连接的协议,所以使用 TCP 前必须先建立连接,而建立连接是通过三次握手来进行的。

TCP 三次握手

  • 一开始,客户端和服务端都处于 CLOSED 状态。先是服务端主动监听某个端口,处于 LISTEN 状态

第一个报文—— SYN 报文

  • 客户端会随机初始化序列号(client_isn),将此序号置于 TCP 首部的序列号字段中,同时把 SYN标志位置为 1 ,表示 SYN报文。接着把第一个 SYN 报文发送给服务端,表示向服务端发起连接,该报文不包含应用层数据,之后客户端处于 SYN-SENT 状态。

第二个报文 —— SYN + ACK 报文

  • 服务端收到客户端的 SYN 报文后,首先服务端也随机初始化自己的序列号(server_isn),将此序列号填入 TCP 首部的序列号字段中,其次把 TCP 首部的确认应答号字段填入 client_isn + 1, 接着把 SYNACK 标志位置为 1。最后把该报文发给客户端,该报文也不包含应用层数据,之后服务端处于 SYN-RCVD 状态。

第三个报文 —— ACK 报文

  • 客户端收到服务端报文后,还要向服务端回应最后一个应答报文,首先该应答报文 TCP 首部 ACK 标志位置为 1 ,其次确认应答号字段填入 server_isn + 1 ,最后把报文发送给服务端,这次报文可以携带客户到服务器的数据,之后客户端处于 ESTABLISHED 状态。
  • 服务器收到客户端的应答报文后,也进入 ESTABLISHED 状态。

从上面的过程可以发现第三次握手是可以携带数据的,前两次握手是不可以携带数据的,这也是面试常问的题。

一旦完成三次握手,双方都处于 ESTABLISHED 状态,此时连接就已建立完成,客户端和服务端就可以相互发送数据了。

4、为什么是三次握手?而不是两次握手或四次握手?

  • 避免资源浪费
  • 同步双方的初始序列号
  • 阻止重复历史连接的初始化

TCP 建立连接时,通过三次握手能防止历史连接的建立,能减少双方不必要的资源开销,能帮助双方同步初始序列号。序列号能够保证数据包不重复、不丢弃和按序传输。

不使用两次握手的原因:两次握手无法防止历史连接的建立,会造成双方资源的浪费,也无法可靠的同步双方序列号。

不使用四次握手的原因:三次握手就已经理论上最少可靠连接建立,所以不需要使用更多的通信次数。

5、TCP的四次挥手

所谓的四次挥手即TCP连接的释放(解除)。连接的释放必须是一方主动释放,另一方被动释放。以下为客户端主动发起释放连接的图解:

image-20210416115520846

  1. 首先客户端想要释放连接,向服务器端发送一段TCP报文,其中:标记位为FIN,表示“请求释放连接“。序号为Seq=u;随后客户端进入FIN-WAIT-1阶段,即半关闭阶段。并且停止在客户端到服务器端方向上发送数据,但是客户端仍然能接收从服务器端传输过来的数据。注意:这里不发送的是正常连接时传输的数据(非确认报文),而不是一切数据,所以客户端仍然能发送ACK确认报文。
  2. 服务器端接收到从客户端发出的TCP报文之后,确认了客户端想要释放连接,随后服务器端结束ESTABLISHED阶段,进入CLOSE-WAIT阶段(半关闭状态)并返回一段TCP报文,其中:标记位为ACK,表示接收到客户端发送的释放连接的请求。序号为Seq=v;确认号为Ack=u+1,表示是在收到客户端报文的基础上,将其序号Seq值加1作为本段报文确认号Ack的值。随后服务器端开始准备释放服务器端到客户端方向上的连接。客户端收到从服务器端发出的TCP报文之后,确认了服务器收到了客户端发出的释放连接请求,随后客户端结束FIN-WAIT-1阶段,进入FIN-WAIT-2阶段前两次挥手既让服务器端知道了客户端想要释放连接,也让客户端知道了服务器端了解了自己想要释放连接的请求。于是,可以确认关闭客户端到服务器端方向上的连接了。
  3. 服务器端自从发出ACK确认报文之后,经过CLOSED-WAIT阶段,做好了释放服务器端到客户端方向上的连接准备,再次向客户端发出一段TCP报文,其中:标记位为FINACK,表示已经准备好释放连接了。注意:这里的ACK并不是确认收到服务器端报文的确认报文。序号为Seq=w;确认号为Ack=u+1。表示是在收到客户端报文的基础上,将其序号Seq值加1作为本段报文确认号Ack的值。随后服务器端结束CLOSE-WAIT阶段,进入LAST-ACK阶段。并且停止在服务器端到客户端的方向上发送数据,但是服务器端仍然能够接收从客户端传输过来的数据。
  4. 客户端收到从服务器端发出的TCP报文,确认了服务器端已做好释放连接的准备,结束FIN-WAIT-2阶段,进入TIME-WAIT阶段,并向服务器端发送一段报文,其中:标记位为ACK,表示接收到服务器准备好释放连接的信号。序号为Seq=u+1。表示是在收到了服务器端报文的基础上,将其确认号Ack值作为本段报文序号的值。确认号为Ack=w+1。表示是在收到了服务器端报文的基础上,将其序号Seq值作为本段报文确认号的值。随后客户端开始在TIME-WAIT阶段等待2MSL

5、为什么连接的时候是三次握手,关闭的时候却是四次挥手?

  1. 因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。
  2. 但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,“你发的FIN报文我收到了”。
  3. 只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。

6、TCP的三次握手一定能保证传输可靠吗?

不能。

  • 三次握手比两次更可靠,但也不是完全可靠,而追加更多次握手也不能使连接更可靠了。因此选择了三次握手。
  • 世界上不存在完全可靠的通信协议。从通信时间成本空间成本以及可靠度来讲,选择了三次握手作为点对点通信的一般规则。

7、为什么客户端在TIME-WAIT阶段要等2MSL?

为的是确认服务器端是否收到客户端发出的ACK确认报文。

当客户端发出最后的ACK确认报文时,并不能确定服务器端能够收到该段报文。所以客户端在发送完ACK确认报文之后,会设置一个时长为2MSL的计时器。MSL指的是Maximum Segment Lifetime:一段TCP报文在传输过程中的最大生命周期。2MSL即是服务器端发出为FIN报文和客户端发出的ACK确认报文所能保持有效的最大时长。

如果服务器端在1MSL内没有收到客户端发出的ACK确认报文,就会再次向客户端发出FIN报文。

如果客户端在2MSL内,再次收到了来自服务器端的FIN报文,说明服务器端由于各种原因没有接收到客户端发出的ACK确认报文。客户端再次向服务器端发出ACK确认报文,计时器重置,重新开始2MSL的计时。否则客户端在2MSL内没有再次收到来自服务器端的FIN报文,说明服务器端正常接收了ACK确认报文,客户端可以进入CLOSED阶段,完成“四次挥手”。所以,客户端要经历时长为2SML的TIME-WAIT阶段;这也是为什么客户端比服务器端晚进入CLOSED阶段的原因。

CATALOG
  1. 1. TCP的三次握手和四次挥手
    1. 1.0.1. 1、TCP简介
    2. 1.0.2. 2、TCP数据报结构
    3. 1.0.3. 3、TCP的三次握手
    4. 1.0.4. 4、为什么是三次握手?而不是两次握手或四次握手?
    5. 1.0.5. 5、TCP的四次挥手
    6. 1.0.6. 5、为什么连接的时候是三次握手,关闭的时候却是四次挥手?
    7. 1.0.7. 6、TCP的三次握手一定能保证传输可靠吗?
    8. 1.0.8. 7、为什么客户端在TIME-WAIT阶段要等2MSL?