深入解析 TCP 连接的三部曲与四部曲,面试答对薪资+5K

前言

在网络技术的深层架构中,“三次握手” 和 “四次挥手”是非常重要的环节,这个环节看似非常难,其实一点也不简单。

  • 三次握手:确保客户端与服务器之间能够可靠地建立连接,为数据的稳定传输奠定基础。
  • 四次挥手:安全、优雅地终止已经完成的数据传输连接,释放相关的资源。

今天我就来深入剖析“三次握手”和“四次挥手”的具体流程和原理,理解了这篇文章,面试时绝对是包加分的。

完整的网络请求步骤全解析

一个完整的网络请求可以分成八大步:

  1. 应用层生成请求: 用户在浏览器中输入网址或进行操作,触发浏览器生成网络请求。
  2. DNS 解析: 浏览器将输入的域名发送到 DNS 服务器,获取对应的 IP 地址。
  3. 建立 TCP 连接(三次握手): 通过传递数据包,建立连接。
  4. 发送 HTTP 请求: 客户端向服务器发送包含请求方法、URI、协议版本、请求头和请求体等信息的 HTTP 请求。
  5. 服务器处理请求: 服务器接收到请求后,进行处理,如查询数据库、执行计算等。
  6. 服务器返回 HTTP 响应: 服务器将处理结果以 HTTP 响应的形式返回给客户端,包括响应状态码、响应头和响应体。
  7. 关闭 TCP 连接(四次挥手): 确保信息完整传递后,关闭连接。
  8. 浏览器解析和渲染: 浏览器接收到响应后,解析 HTML、CSS 和 JavaScript 等资源,进行页面的渲染和展示。

image.png

探秘三次握手与四次挥手

三次握手

  • 第一次握手: 客户端向服务器发送一个 SYN (同步)数据包,该数据包中 SYN 标志位被设置为 1,同时随机选择一个初始序列号(Sequence Number,简称 Seq),例如 Seq = x。此时客户端进入 SYN_SENT 状态。这个 SYN 数据包的目的是请求建立连接,并告知服务器客户端的初始序列号,以便后续的数据传输能够按序进行。

    • SYN 标志位为 1 表示这是一个请求建立连接的数据包
    • 客户端进入 SYN_SENT 状态意味着客户端已经发送了 SYN 数据包,正在等待服务器的响应,处于请求连接但尚未完全建立连接的中间状态。
  • 第二次握手: 服务器接收到客户端的 SYN 数据包后,知道客户端想要建立连接,服务器会向客户端发送一个带有 SYN 和 ACK 标志位的数据包,其中服务器也随机生成一个初始序列号 Seq=y,ACK 的值为客户端的 Seq 值加 1,即 ACK=x + 1。此时服务器进入 SYN_RCVD 状态,表示服务器已经接收到客户端的请求,并等待客户端的确认。

    • ACK 标志位的主要作用是向发送方确认已经成功接收了数据。
    • 在正常情况下,当服务器端收到客户端发送的 SYN(同步)报文后,会向客户端发送 ACK(确认)和 SYN 报文,此时服务器的状态就变为 SYN_RCVD,如果之后再收到客户端的 ACK 报文,就代表完成了三次握手。
  • 第三次握手: 客户端接收到服务器的 SYN+ACK 数据包后,检查 ACK 值是否正确。如果正确,客户端会向服务器发送一个带有 ACK 标志位的数据包,其中 Seq 的值为第一次握手时的 Seq 值加 1,即 Seq=x + 1,ACK 的值为服务器的 Seq 值加 1,即 ACK=y + 1。服务器接收到这个数据包后,检查 ACK 值,如果正确,连接建立成功,客户端和服务器都进入 ESTABLISHED 状态,可以开始进行数据传输。

四次挥手

  • 第一次挥手: 客户端发送一个 FIN 报文段给服务器,报文段的首部中,FIN 标志位被设置为 1,表示请求关闭连接,同时还会包含一个序列号 Seq,假设为 x ,序列号 x 是客户端之前发送的数据的最后一个字节的序号加 1,此时客户端进入 FIN_WAIT_1 状态,等待服务器的回应。

  • 第二次挥手: 服务器收到客户端的 FIN 报文段后,回复一个 ACK 报文段,报文段的首部的 ACK 标志位被设置为 1 ,确认号 Ack 被设置为客户端发送的 FIN 报文段的序列号 x 加 1,同时服务器也会为这个 ACK 报文段分配一个序列号 Seq ,假设为 y 。此时服务器进入 CLOSE_WAIT 状态,表示服务器已经收到客户端的关闭请求,但还可能有数据要继续发送给客户端,客户端收到这个 ACK 报文段后进入 FIN_WAIT_2 状态,继续等待服务器的关闭请求。

  • 第三次挥手: 服务器处理完剩余的数据发送工作后,向客户端发送一个 FIN 报文段。这个 FIN 报文段的首部中,FIN 标志位被设置为 1 ,序列号 Seq 假设为 z (z 是服务器之前发送的数据的最后一个字节的序号加 1 ),此时服务器进入 LAST_ACK 状态,等待客户端的最后确认。

  • 第四次挥手: 客户端收到服务器的 FIN 报文段后,回复一个 ACK 报文段,报文段的 ACK 标志位被设置为 1 ,确认号 Ack 被设置为服务器发送的 FIN 报文段的序列号 z 加 1 ,即 Ack = z + 1 。同时,客户端也会为这个 ACK 报文段分配一个序列号 Seq ,假设为 w (w 通常是客户端之前发送的 ACK 报文段的序列号加 1 ),此时客户端进入 TIME_WAIT 状态,服务器收到客户端的 ACK 报文段后,直接进入 CLOSED 状态。客户端经过 2 倍的最大报文段生存时间(MSL)后,也进入 CLOSED 状态,完成连接的关闭。

    ACK 报文有可能在网络中丢失,导致服务端收不到这个确认信息,如果没有收到客户端的 ACK 报文,就会超时重传 FIN 报文,而客户端在等待 2MSL 时间内,有足够的时间再次收到服务端重传的 FIN 报文,并重新发送 ACK 报文,确保服务端能够正常关闭连接。如果客户端发送 ACK 后不等待 2MSL 就直接进入 CLOSED 状态,那么当服务端重传 FIN 报文时,客户端已经关闭,就无法接收并响应这个 FIN 报文,从而导致服务端无法正常关闭,一直处于 LAST_ACK 状态。

    MSL 是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。客户端等待 2MSL 是为了保证连接的可靠关闭和避免新旧连接的数据包混淆,确保网络通信的正确性和稳定性。

导致三次握手和四次挥手失败的常见错误

三次握手常见的失败原因

  1. 在网络环境不稳定的情况下,SYN、SYN+ACK 或 ACK 数据包可能会延迟到达或丢失,导致超时并使握手失败。

  2. 如果服务器端或客户端要使用的端口已经被其他进程占用,那么新的连接请求可能会失败。

  3. 防火墙或网络中的安全策略可能会阻止某些数据包的传输,干扰三次握手过程。

  4. 当服务器负载过高,资源(如内存、连接数等)不足时,可能无法及时处理新的连接请求。

四次挥手常见的失败原因

  1. 如果一方在未完成挥手过程时突然异常关闭,导致另一方无法收到预期的数据包,会导致挥手失败。

  2. 与三次握手类似,网络延迟、丢包等问题可能导致 FIN 或 ACK 数据包丢失或延迟,影响挥手过程。

  3. 如果一方发送了 FIN 数据包,但另一方长时间未处理,导致超时,也会造成挥手失败。

最后

三次握手建立了可靠的连接,为数据的稳定传输奠定基础;四次挥手则优雅地结束连接释放资源,希望我的这次解析能为你面试提供有力的帮助。