TCP 之 三次握手 (面经计网篇)

这是tcp 简历连接的三次握手方式 , 其中的特殊符号 , 我解释下 , SYN 是 同步的这个单词**(synchronization)** , ACK 是回执,承认的单词**(acknowledgement), SYN-ACK**服务器收到SYN报文后,回复一个带有SYN和ACK标志的报文段,这表示服务器已经收到了客户端的SYN报文,并且期望收到下一个字节的序列号为服务器传递的确认号。拓展1,2,3 (介绍三个报文)

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

在前面我们知道了什么是 TCP 连接

  • 用于保证可靠性和流量控制维护的某些状态信息,这些信息的组合,包括 Socket、序列号和窗口大小称为连接。

所以,重要的是为什么三次握手才可以初始化 Socket、序列号和窗口大小并建立 TCP 连接。

接下来,以三个方面分析三次握手的原因:

  • 三次握手才可以阻止重复历史连接的初始化(主要原因)
  • 三次握手才可以同步双方的初始序列号
  • 三次握手才可以避免资源浪费 (面经是这样的,但我个人感觉 , 1 和 3 是可以合并的,具体讲到了,再说)、

原因一:避免历史连接

我们来看看 RFC 793 指出的 TCP 连接使用三次握手的首要原因

The principle reason for the three-way handshake is to prevent old duplicate connection initiations from causing confusion.

简单来说,三次握手的首要原因是为了防止旧的重复连接初始化造成混乱。

我们考虑一个场景,客户端先发送了 SYN(seq = 90)报文,然后客户端宕机了,而且这个 SYN 报文还被网络阻塞了,服务端并没有收到,接着客户端重启后,又重新向服务端建立连接,发送了 SYN(seq = 100)报文(注意!不是重传 SYN,重传的 SYN 的序列号是一样的 )。(这里 ,我需要自习讲解一下 只有客户端爆掉了,或者客户端出现特殊情况了,序列号才会传递一个新的 。 不然都是重传序列号

上述中的「旧 SYN 报文」称为历史连接,TCP 使用三次握手建立连接的最主要原因就是防止「历史连接」初始化了连接

这里也说明了,为什么不是两次握手:

如果是两次握手连接,就无法阻止历史连接,那为什么 TCP 两次握手为什么无法阻止历史连接呢?

我先直接说结论,主要是因为在两次握手的情况下,服务端没有中间状态给客户端来阻止历史连接,导致服务端可能建立一个历史连接,造成资源浪费

可以看到,如果采用两次握手建立 TCP 连接的场景下,服务端在向客户端发送数据前,并没有阻止掉历史连接,导致服务端建立了一个历史连接,又白白发送了数据,妥妥地浪费了服务端的资源。

因此,要解决这种现象,最好就是在服务端发送数据前,也就是建立连接之前,要阻止掉历史连接,这样就不会造成资源浪费,而要实现这个功能,就需要三次握手

所以,TCP 使用三次握手建立连接的最主要原因是防止「历史连接」初始化了连接。

原因二:同步双方初始序列号

TCP 协议的通信双方, 都必须维护一个「序列号」, 序列号是可靠传输的一个关键因素,它的作用:

  • 接收方可以去除重复的数据;
  • 接收方可以根据数据包的序列号按序接收;
  • 可以标识发送出去的数据包中, 哪些是已经被对方收到的(通过 ACK 报文中的序列号知道);

这里回答了,为什么不是四次握手:

三次,四次握手都是为了维持序列号的统一, 但看了下图,你就明白了,三次可以完成,为什么要四次来完成呢?

原因三:避免资源浪费:

这就是,我在前面说的可以和第一点合并,为什么呢?因为如果,没有防止到历史连接,自然就会有很多的序列号存在,所以,减少了历史链接,自然就避免了资源浪费 (这个"避免资源的浪费 , 基本上可以说是万金油答案")而且还有 我自己的一些理解 ,就是通过从四次握手,减少到三次握手,会不会也减少了浪费资源

若在,握手的过程中,丢失的话,会有什么影响吗?

第一次握手丢失了,会发生什么?

当 客户端 想和 服务端 想建立连接时,首先 , 第一次先发送SYN 报文,进入SYN-SENT 状态

在这之后,如果客户端迟迟收不到服务端的 SYN-ACK 报文(第二次握手)就会触发「超时重传」机制,重传 SYN 报文,而且重传的 SYN 报文的序列号都是一样的

通常 ,第一次超时重传是在1秒后,第二次超时重传是在2秒,第三次超时重传是在4秒后,第四次超时重传是在 8秒后,第五次是在超时重传 16 秒后。没错,每次超时的时间是上一次的 2倍

第二次握手丢失了,会发生什么?

当服务端收到客户端的第一次握手后,就会回 SYN-ACK 报文给客户端,这个就是第二次握手,此时服务端会进入 SYN RCVD 状态。

第二次握手的 SY-ACK 报文其实有两个目的:

  1. 第二次握手里的 ACK,是对第一次握手的确认报文;
  2. 第二次握手里的 SYN,是服务端发起建立 TCP 连接的报文,

所以,如果第二次握手丢了,就会发生比较有意思的事情,具体会怎么样呢?

因为第二次握手报文里是包含对客户端的第一次握手的 ACK 确认报文,所以,如果客户端 迟迟没有收到第二次握手,那么客户端就觉得可能自己的 SYN 报文(第一次握手)丢失了,于是客户端就会触发超时重传机制,重传 SYN 报文 。

然后,因为第二次握手中包含服务端的 SYN 报文,所以当客户端收到后,需要给服务端发送 ACK 确认报文(第三次握手),服务端才会认为该 SYN 报文被客户端收到了。那么,如果第二次握手丢失了,服务端就收不到第三次握手,于是服务端这边会触发超时重传机制,重传SYN-ACK 报文。

因此,当第二次握手丢失了,客户端和服务端都会重传:

  • 客户端会重传 SYN 报文,也就是第一次握手,最大重传次数由 tcp_syn_retries 内核参数决定
  • 服务端会重传 SYN-ACK 报文,也就是第二次握手,最大重传次数出 tcp_synack_retries 内核参数决定。

第三次握手丢失了,会发生什么?

客户端收到服务端的 SYN-ACK 报文后,就会给服务端回一个 ACK 报文,也就是第三次握手,此时客户端状态进入到 ESTABLISH 状态

因为这个第三次握手的 ACK 是对第二次握手的 SYN 的确认报文,所以当第三次握手丢失了,如果服务端那一方迟迟收不到这个确认报文,就会触发超时重传机制,重传SYN-ACK 报文,直到收到第三次握手或者达到最大重传次数。

注意,ACK 报文是不会有重传的,当 ACK丢失了,就由对方重传对应的报文

举个例子,假设 tcp_synack_retries 参数值为 2,那么当第三次握手一直丢失时,发生的过程如下图:

上诉都参考我之前看过的文章

拓展 1 :

拓展 2 :

拓展 3 :

相关推荐
bigbig猩猩7 分钟前
intellij idea创建java项目
java·ide·intellij-idea
Z.Virgil9 分钟前
【案例70】invalid secrity token(null)
java·linux·websphere
不会八股文16 分钟前
SpringBoot集成Thymeleaf模板引擎,为什么使用(详细介绍)
java·spring boot·后端
小扳20 分钟前
Redis 篇-深入了解使用 Redis 中的 GEO 数据结构实现查询附近店铺、BitMap 实现签到功能、HyperLogLog 实现 UV 流量统计
java·数据库·redis·后端·缓存
ChinaRainbowSea36 分钟前
十一,Spring Boot 当中配置拦截器的“两”种方式
java·spring boot·后端·spring·web
ChinaRainbowSea38 分钟前
十二,Spring Boot 异常处理(自定义异常页面,全局异常,自定义异常)
java·spring boot·后端·spring·web
入秋的大橘38 分钟前
Spring Boot 集成 Redisson 实现消息队列
java·spring boot·后端
罗伯特_十三1 小时前
Java 单例模式
java·开发语言·单例模式