loading

为什么TCP要三次握手而不是两次

# TCP的三次握手本质上是通信双方交换彼此的序列号

一开始,客户端处于 closed 的状态,服务端处于 listen 的状态

  • 第一次握手:客户端发送请求报文SYN,包含客户端的初始序列号ISN,请求发送后,客户端便进入 SYN-SENT 状态。
  • 第二次握手:服务端接收到请求后,返回根据客户端的初始序列号生成的应答报文ACK(把客户端的 ISN + 1 作为ACK 的值),以自己的 SYN 报文作为应答,和服务端的初始序列号ISN,发送完成后便进入 SYN-RECEIVED 状态。
  • 第三次握手:客户端收到 SYN 报文之后,会发送一个 ACK 报文,当然,也是一样把服务器的 ISN + 1 作为 ACK 的值,表示已经收到了服务端的 SYN 报文,此时客户端处于 ESTABLISHED 状态。服务器收到 ACK 报文之后,也处于 ESTABLISHED 状态,此时,双方已建立起了连接。

# 两次握手的情况

  • 一个「旧 SYN 报文」比「最新的 SYN 」 报文早到达了服务端;
  • 那么此时服务端就会回一个 SYN + ACK 报文给客户端;
  • 客户端收到后可以根据自身的上下文,判断这是一个历史连接(序列号过期或超时),那么客户端就会发送 RST 报文给服务端,表示中止这一次连接。

如果是两次握手连接,就不能判断当前连接是否是历史连接,为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误,三次握手则可以在客户端(发送方)准备发送第三次报文时,客户端因有足够的上下文来判断当前连接是否是历史连接:

# 序列号是干嘛的

  • TCP 协议的通信双方, 都必须维护一个「序列号」, 序列号是可靠传输的一个关键因素,它的作用:
  • 接收方可以去除重复的数据;
  • 接收方可以根据数据包的序列号按序接收;
  • 可以标识发送出去的数据包中, 哪些是已经被对方收到的;
  • 当客户端发送携带「初始序列号」的 SYN 报文的时候,需要服务端回一个 ACK 应答报文,表示客户端的 SYN 报文已被服务端成功接收,那当服务端发送「初始序列号」给客户端的时候,依然也要得到客户端的应答回应,这样一来一回,才能确保双方的初始序列号能被可靠的同步

# 那四次握手呢

  • 四次握手其实也能够可靠的同步双方的初始化序号,但由于服务端发送请求连接报文和确认应答报文可以优化成一步,所以就成了「三次握手」。

  • 而两次握手只保证了一方的初始序列号能被对方成功接收,没办法保证双方的初始序列号都能被确认接收

# 四次挥手的过程

  • 客户端发送一个 FIN,用来关闭客户端到服务器的数据传送;发送连接释放请求。
  • 服务器收到这个 FIN,它发回一个 ACK,确认序号为收到的序号加 1。和 SYN 一样,一个 FIN 将占用一个序号;
  • 服务器关闭与客户端的连接,发送一个FIN给客户端;
  • 客户端发回 ACK 报文确认,并将确认序号设置为收到序号加 1。

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

  • 建立连接时,因为服务端在 LISTEN 状态下,收到建立连接请求的 SYN 报文后,把 ACK 和 SYN 放在一个报文里发送给客户端。

  • 而关闭连接时,当收到对方的 FIN 报文时,仅表示对方不再发送数据但还能接收收据,我们也未必把全部数据都发给了对方,所以我们可以立即 close,也可以发送一些数据给对方后,再发送 FIN 报文给对方表示同意关闭连接。因此我们的 ACK 和 FIN 一般会分开发送。

# TCP 协议如何保证可靠传输

TCP协议保证数据传输可靠性的方式主要有:

  • 校验和: TCP 将保持它首部和数据的检验和。这是一个端到端的检验和,目的是检测数据在传输过程中的任何变化。如果收到段的检验和有差错,TCP 将丢弃这个报文段和不确认收到此报文段。
  • 确认应答+序列号(累计确认+seq)。接收方收到报文就会确认(累积确认:对所有按序接收的数据的确认),TCP 给发送的每一个包进行编号,接收方对数据包进行排序,把有序数据传送给应用层。TCP 的接收端会丢弃重复的数据。
  • 流量控制: TCP 连接的每一方都有固定大小的缓冲空间,TCP的接收端只允许发送端发送接收端缓冲区能接纳的数据。当接收方来不及处理发送方的数据,能提示发送方降低发送的速率,防止包丢失。TCP 使用的流量控制协议是可变大小的滑动窗口协议。 (TCP 利用滑动窗口实现流量控制)
  • 拥塞控制: 当网络拥塞时,减少数据的发送。 停止等待协议 也是为了实现可靠传输的,它的基本原理就是每发完一个分组就停止发送,等待对方确认。在收到确认后再发下一个分组。
  • 超时重传: 当 TCP 发出一个段后,它启动一个定时器,等待目的端确认收到这个报文段。如果不能及时收到一个确认,将重发这个报文段。

个人博客:wudeh (opens new window)

最近更新时间: 2021/08/25 17:25:09
最近更新
01
2023/07/03 00:00:00
02
2023/04/22 00:00:00
03
2023/02/16 00:00:00