面试官:为什么TCP握手需要三次?两次不行吗?

问题:TCP 为什么需要三次握手,两次不行吗?

解答:
TCP(传输控制协议)的三次握手是建立可靠连接的关键步骤。它确保了通信双方在数据传输之前能够确认彼此的存在、状态和能力。虽然看起来两次握手似乎也能完成连接建立,但三次握手有其必要性,主要是为了防止“旧的重复连接请求”导致的问题,并确保双方都能正确接收和发送数据。

1. 三次握手的过程

TCP 的三次握手过程如下:

  1. 第一次握手(SYN)

    • 客户端向服务器发送一个 SYN(同步序列编号)报文段,表示请求建立连接。
    • 客户端进入 SYN_SENT 状态,等待服务器的响应。
  2. 第二次握手(SYN-ACK)

    • 服务器收到客户端的 SYN 报文后,向客户端发送一个 SYN-ACK(同步确认)报文段,表示同意建立连接。
    • 服务器进入 SYN_RECV 状态,等待客户端的最终确认。
  3. 第三次握手(ACK)

    • 客户端收到服务器的 SYN-ACK 报文后,向服务器发送一个 ACK(确认)报文段,表示确认收到服务器的响应。
    • 客户端进入 ESTABLISHED 状态,连接正式建立。
    • 服务器收到 ACK 后也进入 ESTABLISHED 状态,连接正式建立。

2. 为什么需要三次握手?

2.1 防止旧的重复连接请求

  • 问题场景:假设客户端 A 向服务器 B 发送了一个连接请求,但由于网络延迟或丢包,这个请求没有及时到达服务器。客户端 A 可能会重新发起连接请求。如果此时服务器 B 收到了第一个请求并建立了连接,而客户端 A 以为连接未成功,再次发送请求,服务器 B 可能会误认为这是一个新的连接请求,导致多个重复的连接。
  • 解决方案:通过三次握手,服务器可以在发送 SYN-ACK 后等待客户端的最终确认(ACK)。如果客户端没有发送 ACK,服务器可以认为连接未成功建立,从而避免创建无效的连接。这样可以防止旧的、重复的连接请求导致的混乱。

2.2 确保双方都能发送和接收数据

  • 问题场景:如果只进行两次握手,可能会出现一种情况:客户端发送了 SYN,服务器发送了 SYN-ACK,但客户端的 ACK 没有到达服务器。此时,客户端认为连接已经建立,开始发送数据,但服务器并没有收到 ACK,因此它不知道客户端是否准备好接收数据。
  • 解决方案:通过第三次握手,客户端明确告诉服务器“我已经收到了你的 SYN-ACK,并且我准备好了”,服务器只有在收到 ACK 后才会进入 ESTABLISHED 状态,确保双方都准备好进行数据传输。

2.3 同步序列号

  • 问题场景:TCP 是基于字节流的协议,每个数据包都有一个序列号,用于确保数据的顺序和完整性。如果只进行两次握手,双方可能无法准确同步序列号,导致后续的数据传输出现问题。
  • 解决方案:通过三次握手,客户端和服务器可以在建立连接时同步各自的初始序列号(ISN)。客户端在 SYN 报文中发送自己的初始序列号,服务器在 SYN-ACK 中确认并发送自己的初始序列号,客户端再通过 ACK 确认收到服务器的序列号。这样,双方都可以准确地跟踪数据包的顺序,确保数据传输的可靠性。

3. 为什么两次握手不行?

如果我们只进行两次握手,可能会遇到以下问题:

  • 客户端无法确认服务器的状态:客户端发送 SYN,服务器发送 SYN-ACK,但客户端无法确认服务器是否真的收到了它的 SYN 报文。如果服务器的 SYN-ACK 丢失,客户端可能会认为连接已经建立,但实际上服务器并没有准备好。
  • 服务器无法确认客户端的状态:服务器发送 SYN-ACK 后,无法确认客户端是否收到了这个报文。如果客户端的 ACK 丢失,服务器可能会认为连接已经建立,但实际上客户端并没有准备好接收数据。
  • 旧的连接请求可能导致问题:如前所述,旧的、重复的连接请求可能会导致服务器创建无效的连接,浪费资源并引发混乱。

4. 实例:两次握手的潜在问题

假设我们使用两次握手来建立 TCP 连接:

  1. 客户端 A 向服务器 B 发送 SYN,请求建立连接。
  2. 服务器 B 收到 SYN,并向客户端 A 发送 SYN-ACK,表示同意建立连接。

在这种情况下,客户端 A 和服务器 B 都认为连接已经建立,但实际上可能存在以下问题:

  • 如果客户端 A 的 SYN 报文在网络中丢失,服务器 B 会收到一个来自客户端 A 的重复 SYN,并再次发送 SYN-ACK。这会导致服务器 B 创建多个重复的连接。
  • 如果服务器 B 的 SYN-ACK 报文在网络中丢失,客户端 A 会认为连接已经建立,开始发送数据,但服务器 B 并没有准备好接收数据,导致数据丢失或混乱。

5. 进一步探讨

  1. 你是否理解为什么三次握手中的每个步骤都是必要的?
    每个步骤都有其特定的作用:第一次握手用于客户端发起连接请求,第二次握手用于服务器确认并发送自己的初始序列号,第三次握手用于客户端确认收到服务器的响应并进入连接状态。
  2. TCP 的四次挥手是什么?它与三次握手有什么不同?
    TCP 的四次挥手是用于关闭连接的过程。与三次握手不同,四次挥手是为了确保双方都能安全地关闭连接,避免数据丢失。每次挥手都涉及到一方发送 FIN(终止)报文,另一方发送 ACK 确认,确保双方都同意关闭连接。
  3. UDP 为什么不需要三次握手?
    UDP 是无连接的协议,它不保证数据的可靠传输,也不需要建立连接。因此,UDP 不需要三次握手。相反,UDP 的设计目标是提供快速、轻量级的通信,适用于对实时性要求较高的场景,如视频流、在线游戏等。

问题:那TCP为什么需要四次挥手?

解答:
TCP 的四次挥手(也称为“四次挥手断开连接”或“FIN-ACK 交换”)是 TCP 协议用于安全、可靠地关闭连接的过程。与三次握手类似,四次挥手确保了双方都能正确地关闭连接,并且在关闭过程中不会丢失数据。那么,为什么 TCP 需要四次挥手而不是两次或三次呢?这主要是为了确保双方都能独立地完成数据传输,并且在关闭连接时不会遗漏任何未发送的数据。

1. 四次挥手的过程

TCP 的四次挥手过程如下:

  1. 第一次挥手(FIN)

    • 客户端 A 发送一个 FIN(终止)报文段给服务器 B,表示客户端 A 没有更多的数据要发送,请求关闭连接。
    • 客户端 A 进入 FIN_WAIT_1 状态,等待服务器 B 的确认。
  2. 第二次挥手(ACK)

    • 服务器 B 收到客户端 A 的 FIN 报文后,发送一个 ACK(确认)报文段给客户端 A,表示已经收到了 FIN 报文。
    • 服务器 B 进入 CLOSE_WAIT 状态,等待应用程序决定是否关闭连接。
    • 客户端 A 收到 ACK 后进入 FIN_WAIT_2 状态,等待服务器 B 发送 FIN
  3. 第三次挥手(FIN)

    • 服务器 B 在完成自己的数据发送后,向客户端 A 发送一个 FIN 报文段,表示服务器 B 也没有更多的数据要发送,请求关闭连接。
    • 服务器 B 进入 LAST_ACK 状态,等待客户端 A 的最终确认。
  4. 第四次挥手(ACK)

    • 客户端 A 收到服务器 B 的 FIN 报文后,发送一个 ACK 报文段给服务器 B,表示已经收到了 FIN 报文。
    • 客户端 A 进入 TIME_WAIT 状态,等待一段时间(通常是两个最大报文生存时间,2MSL),以确保服务器 B 收到了 ACK,然后正式关闭连接。
    • 服务器 B 收到 ACK 后进入 CLOSED 状态,连接正式关闭。

2. 为什么需要四次挥手?

2.1 确保双向通信的完整性

  • 问题场景:TCP 是全双工协议,意味着双方可以同时发送和接收数据。因此,在关闭连接时,双方都需要独立地通知对方自己不再发送数据,并且确认对方已经收到所有数据。

  • 解决方案:通过四次挥手,双方可以分别发送 FIN 和 ACK,确保每个方向的通信都得到了正确的关闭。具体来说:

    • 第一次和第二次挥手确保了客户端 A 不再发送数据,服务器 B 已经收到并确认。
    • 第三次和第四次挥手确保了服务器 B 不再发送数据,客户端 A 已经收到并确认。

2.2 防止数据丢失

  • 问题场景:如果只进行两次或三次挥手,可能会导致一方认为连接已经关闭,而另一方还在发送数据。例如,客户端 A 发送 FIN 后,服务器 B 可能还有未发送的数据。如果此时直接关闭连接,服务器 B 的数据将会丢失。
  • 解决方案:通过四次挥手,服务器 B 可以在发送完所有数据后再发送 FIN,确保所有数据都已成功传输。客户端 A 也可以在收到服务器 B 的 FIN 后确认收到所有数据,然后再发送 ACK 关闭连接。

2.3 处理半关闭状态

  • 问题场景:TCP 允许一方关闭输出流(即不再发送数据),但仍然可以接收来自另一方的数据。这种状态称为“半关闭”(half-close)。例如,客户端 A 可能已经完成了数据发送,但服务器 B 还有数据要发送。
  • 解决方案:通过四次挥手,客户端 A 可以先发送 FIN 关闭输出流,服务器 B 收到 FIN 后可以继续发送数据,直到它也完成了数据发送并发送 FIN。这样,双方都可以独立地完成数据传输,而不会影响对方的正常工作。

2.4 确保连接完全关闭

  • 问题场景:在网络中,数据包可能会延迟或丢失。如果只进行两次或三次挥手,可能会导致一方认为连接已经关闭,而另一方还没有收到确认,从而导致连接没有真正关闭。
  • 解决方案:通过四次挥手,双方可以确保彼此都收到了所有的 FIN 和 ACK 报文,确保连接完全关闭。特别是客户端 A 在进入 TIME_WAIT 状态后,会等待一段时间(2MSL),以确保服务器 B 收到了最后一个 ACK,避免连接被意外重用。

3. 为什么两次或三次挥手不行?

如果我们只进行两次或三次挥手,可能会遇到以下问题:

  • 数据丢失:如果客户端 A 发送 FIN 后,服务器 B 还有未发送的数据,直接关闭连接会导致这些数据丢失。
  • 连接未完全关闭:如果一方没有收到对方的 ACK,可能会认为连接还没有关闭,导致连接资源无法释放,浪费系统资源。
  • 半关闭状态无法处理:如果只进行两次或三次挥手,无法处理一方已经完成数据发送,而另一方仍在发送数据的情况。这会导致连接无法正常关闭,或者数据传输不完整。

4. 实例:两次或三次挥手的潜在问题

假设我们使用两次或三次挥手来关闭 TCP 连接:

  1. 客户端 A 发送 FIN,请求关闭连接。
  2. 服务器 B 收到 FIN,发送 ACK 确认,并立即关闭连接。

在这种情况下,可能会出现以下问题:

  • 如果服务器 B 还有未发送的数据,这些数据将会丢失,因为服务器 B 认为连接已经关闭。
  • 如果客户端 A 没有收到服务器 B 的 ACK,它可能会认为连接还没有关闭,导致连接资源无法释放。
  • 如果服务器 B 没有收到客户端 A 的 ACK,它可能会认为连接还没有关闭,导致连接资源无法释放。

5. 进一步探讨

  1. 你是否理解为什么四次挥手中的每个步骤都是必要的?
    每个步骤都有其特定的作用:第一次和第二次挥手确保客户端 A 不再发送数据,服务器 B 已经收到并确认;第三次和第四次挥手确保服务器 B 不再发送数据,客户端 A 已经收到并确认。这样可以确保双方都能独立地完成数据传输,并且在关闭连接时不会遗漏任何未发送的数据。
  2. TIME_WAIT 状态的作用是什么?
    TIME_WAIT 状态是为了确保服务器 B 收到了客户端 A 的最后一个 ACK。在 TIME_WAIT 状态下,客户端 A 会等待一段时间(通常是两个最大报文生存时间,2MSL),以确保网络中的所有 FIN 和 ACK 报文都已经到达对方,避免连接被意外重用。这是 TCP 协议中非常重要的机制,确保了连接的安全关闭。
  3. UDP 为什么不需要四次挥手?
    UDP 是无连接的协议,它不保证数据的可靠传输,也不需要建立连接。因此,UDP 不需要四次挥手。相反,UDP 的设计目标是提供快速、轻量级的通信,适用于对实时性要求较高的场景,如视频流、在线游戏等。由于 UDP 不保证数据的顺序和完整性,关闭连接时也不需要复杂的握手过程。
全部评论
接好运
点赞 回复 分享
发布于 昨天 18:14 北京
点赞 回复 分享
发布于 昨天 23:45 广东
我不是很能理解,如果syn或者syn–ack在网络上丢失了,那接收方应该就收不到信号了啊。也就不会建立连接了,怎么会导致重复建立呢?
点赞 回复 分享
发布于 今天 12:53 江苏

相关推荐

今天 14:31
已编辑
华中科技大学 前端工程师
一面:1. 算法题- 一个处理项目依赖关系的题,但是本质是树的BFS,20分钟完成- 一道动态规划没写出来,花了半个小时2. 项目- 依次问简历的项目和自己写的亮点- rem布局- 为什么用svelte写项目- 聊聊Graphql和Restfulapi的区别- 双语切换是怎么实现的3. 前端基础- 跨域,我回答了让后端加中间件,然后有深入问我原理,不会- js事件循环- 问我react和vue更喜欢哪一个,为什么- 问我有没有不用框架写过原生小程序4. 唠嗑- 问我除了前端还学过其他方向的东西没- 问我的兴趣爱好- 让我讲讲自己最近看的一部电影(蚌埠住了)- 唠嗑一面挺轻松愉快的,面试官人超级好,经常聊着聊着两个人就不约而同的笑了,刚面完不到一个小时就约了二面。二面1.算法题- 因为一面的动态规划没写出来,所以二面又出了一道动态规划。我一开始当成一维dp了,后来在面试官的提醒下改成二维dp了2. 自我介绍3. 项目    - 问了一下项目内容,主要是小程序    - 细问了一下动画相关的知识        - css3是如何利用GPU加速的        - 如果动画卡顿如何debug    - 问了一下Graphql的知识。        - Graphql相比于RestfulAPI的优点    - 问我除了前端还学过啥    - zustand比redux好在哪里。我答了不用记模板代码,使用方便,然后问我zustand的原理,我说没有深入了解过,猜测是使用了react的原生hook,useContext实现的4. 前端    - 问了一下我最喜欢的框架和原因,我回答是React:        - 生态丰富        - 引入了函数式的思想,我觉得比以前的面向对象更好,我更欣赏这种对行业有引领作用的团队    - 问了一下Taro框架的作用。我答的是利用虚拟DOM编译成对应的代码,但面试官还想问一点原生的东西,我没有用原生的语法写过小程序就没有深入了    - js事件循环5. 计算机基础    - 虚拟内存,快表二面面试官是两位,没有给人很大的压迫感,但是问的很多东西确实都难到我了。给我的感觉是腾讯不爱问八股,更喜欢通过一些项目里的实际问题去考察你。二面不出意外的挂了
查看25道真题和解析
点赞 评论 收藏
分享
目前这家已经离职了,想着要不要再找一份可以转正的实习,想着all in春招,春招之后再找实习,但是又没把握春招能拿到offer。现在已经有一段实习了,7月到12月,当时all in转正,但是没得,也错过了秋招。现在问题就是说在学校,临港,不租房的话通勤来回得5 6个小时,租房又得倒贴实习,实习的话又没有经历去准备春招了。其实也是有可能毕业后往广东那边发展的,离家近一点,但是也就深圳java岗好一些。佬们路过能给晚辈一点建议吗。
黑皮白袜臭脚体育生:有实习经历除非到春招前能找到比实习经历title好的多的公司,不建议再找一段实习了,拿这段时间出来沉淀allin春招,春招后期还有补录,虽然机会不多但同样的竞争对手也不会多了,其实和春招高峰期相比拿offer难度差距不大,实在没拿到正式offer到五月份还有招25届的转正实习,再不行25届还能进一些接收应届生的社招岗,都有机会的另外宣传下自己的开源仿b站微服务项目,GitHub已经390star,牛客上有完整文档教程,如果觉得有帮助的话可以点个小星星,蟹蟹
点赞 评论 收藏
分享
评论
8
18
分享
牛客网
牛客企业服务