TCP 面试题 — TCP 握手为什么是三次,为什么不能是两次?不能是四次?
🚀 大家好,我是小康。
今天给大家分享一个 TCP 面试题 :TCP 握手为什么是三次,为什么不能是两次?不能是四次?
小技巧:在面试中,可以参考下面的示例回答,这样回答简洁明了。详细介绍部分则是为了帮助大家系统学习,以便应对面试官深入提问。
示例回答:
TCP三次握手确保双方准备好通信,防止旧连接误用,同步双方初始序列号,并避免资源浪费。两次握手无法确保双方都准备好,无法防止旧连接的建立,导致序列号不同步和资源浪费,而四次握手则增加了不必要的复杂性和延迟。三次握手在确保连接可靠性的同时,也保持了高效性。
详细解释
为什么是三次握手?
1、确保双方都准备好
解释:三次握手通过三步过程确认双方都准备好进行数据传输。客户端发送 SYN 包,服务器回复 SYN-ACK 包,客户端再发送 ACK 包。这样,双方都能确认彼此的存在和状态。
类比:点头确认
想象你和朋友要在远处确认是否准备好开始对话,你们用点头来确认彼此的状态。这类似于TCP的三次握手。
点头确认过程(TCP三次握手)
- 第一次握手:你点头
- 你朝朋友点头,意思是:“我准备好和你说话了。”(SYN包)
- 第二次握手:朋友点头
- 朋友看到你的点头,朝你点头回应:“我也准备好了,你听到了吗?”(SYN-ACK包)
- 第三次握手:你再次点头
- 你看到朋友的点头,再次点头回应:“我听到了,我们开始吧。”(ACK包)
通过这个过程,你和朋友可以确保彼此都准备好,并且都知道对方也准备好。这避免了通信中的混乱和误解。
如果通信过程只有两次握手,那这样的通信过程可能会存在一些问题 :
- 你无法确认朋友是否收到了你对他准备好的确认:在三次握手中,你的最后一次点头(发送ACK包)是告诉朋友你已经收到他的回应,并确认你们两个都明白对方已经准备好开始对话。如果没有这一步,虽然你知道朋友准备好了,但朋友并不知道你是否真的收到了他的准备信号,这可能会导致他在你还没有完全准备好的情况下就开始讲话。
这就是为什么TCP需要三次握手来建立连接。这确保了双方不仅知道对方已经准备好,而且确认了彼此都收到了对方的准备好的信息,从而有效避免了通信的混乱和误解。
2、防止重复历史连接的初始化
解释:通过三次握手,可以确保当前的连接请求是新的,而不是旧的或重复的请求。这是因为每次握手都有新的序列号,确保了连接的唯一性和正确性。
场景设定:
想象你和朋友通过传纸条的方式进行通信,每次通信都需要确认对方已经准备好,并且要避免误读之前的旧纸条。
三次握手过程:
- 第一次握手:你写了一张纸条给朋友,内容是:“我们开始通信吧。”(SYN包)
- 第二次握手:朋友收到纸条后,回了一张纸条给你,内容是:“好的,我收到你的信息了,我们开始吧。”(SYN-ACK包)
- 第三次握手:你收到朋友的纸条后,再回一张纸条给朋友,内容是:“太好了,那我们正式开始通信。”(ACK包)
防止重复历史连接:
现在假设一个特殊情况:几天前你曾给朋友发过一张“我们开始通信吧”的纸条(SYN包),但是由于某些原因这张纸条在传递过程中被延误了,朋友没有及时收到。所以你们那次通信并没有成功。
几天后,这张旧纸条(SYN包)终于到了朋友手中。如果只有2次握手而没有三次握手的确认机制的话,朋友可能会误以为这是新的通信请求,直接开始通信,这样就会导致混乱,因为他以为你们是在旧的基础上开始的。
通过三次握手:
- 第一次握手时,你发送请求。
- 第二次握手时,朋友收到请求并确认准备开始通信。
- 第三次握手时,你确认朋友的准备并正式开始通信。
这三次确认确保了双方都知道当前的通信请求是新的,而不是基于旧的历史纸条。这就防止了网络中滞留的旧请求包被误认为是新的通信请求。
3、同步双方的初始序列号
TCP三次握手的过程中同步双方的初始序列号是非常关键的一步,这对后续数据传输中的顺序控制和数据完整性非常重要。
先说下序列号的作用:在TCP连接中,每个字节的数据都会被赋予一个序列号,这有助于接收方正确、有序地重组来自发送方的数据。如果数据包在网络中丢失或到达顺序不正确,接收方可以根据序列号重组原始数据。
类比实际例子:
想象两个朋友A和B在玩一个游戏,他们需要互相发送确认信息来同步游戏进度。
三次握手过程(TCP连接建立)
1、第一次握手(A -> B):A发送一条信息给B:“我在游戏中的进度是第10关。”(相当于TCP中的SYN报文,包含A的初始序列号)
2、第二次握手(B -> A):B收到信息后,回复A:“我知道了,我在游戏中的进度是第20关。”(相当于TCP中的SYN-ACK报文,包含B的初始序列号,并确认收到A的进度信息)
如果只进行这两次握手,A无法确认B是否正确收到了他的进度信息。如果B的回复在传输过程中丢失,A会一直等待B的确认,而B则认为A已经收到了他的进度信息。在这种情况下,A和B的游戏进度可能不同步,导致游戏进度出现混乱。
三次握手的解决方案
通过三次握手,确保双方的初始序列号同步,避免通信中的不确定性和误解。
3、第三次握手(A -> B):A收到B的进度信息后,回复:“好的,我收到了你的进度信息。”(相当于TCP中的ACK报文,确认收到B的SYN-ACK报文)
这样,B可以确认A确实收到了他的进度信息,确保双方的游戏进度同步。
总结:通过三次握手,TCP协议确保双方的初始序列号同步,避免了只进行两次握手可能导致的序列号不同步问题。这个过程类似于两个朋友互相确认游戏进度的过程,确保双方的信息一致,从而避免通信中的不确定性和误解。
4、避免资源浪费
解释:通过三次握手,服务器在确认客户端已准备好进行通信前不会分配大量资源。这有效避免了资源的浪费。
类比会议室预订:
想象一下,你想预订一间会议室来举办一个会议。这个预订过程和TCP三次握手很相似:
- 提出预订请求(第一次握手):
- 你给管理会议室的管理员发送一条信息:“我想在明天的上午9点到11点使用会议室。”
- 这就像发送一个SYN包,表示你想开始一个连接。
- 管理员确认并提出条件(第二次握手):
- 管理员回复你:“好的,会议室明天上午9点到11点可用。请确认你会准时到达并使用。”
- 这就像服务器发送SYN和ACK,不仅确认了你的请求,还提出了自己的条件(即服务器的初始序列号)。
- 你最终确认(第三次握手):
- 你回复管理员:“我确认,我会准时到达并使用会议室。”
- 这就是你发送ACK,确认管理员的条件,完成连接建立。
如果只有两次握手会发生什么?
1、预订资源浪费:
- 管理员以为你会使用会议室,但你并没有确认。如果你没有收到管理员的回复而没有去使用会议室,会议室会空置,导致资源浪费。在TCP中,这会导致服务器预留内存。
2、重复预订:
- 如果你的请求在网络中延迟,管理员在不知情的情况下收到你的旧请求,可能会重复确认预订,导致混乱和资源浪费。在TCP中,这会导致服务器为多个无效连接预留内存和连接表空间。
3、未能成功建立连接:
- 如果你没有收到管理员的确认(第二次握手),你可能会认为预订未成功,再次发送请求,造成不必要的重复操作和资源消耗。在TCP中,这会导致服务器浪费处理能力和带宽。
通过这个比喻,我们可以看到TCP三次握手如同一种精确的确认过程,它确保所有资源(如会议室或网络连接)都是在双方明确同意并准备好的情况下才被使用,有效地防止了资源的浪费。
TCP为什么不是四次握手?
增加不必要的复杂性
- 解释:四次握手会增加额外的确认步骤,使连接建立的过程更加复杂。每增加一次握手,都会引入更多的确认和等待步骤,增加协议的复杂性。
- 类比:想象你和朋友确认一起吃晚饭。三次握手类似于:你发短信问(SYN),朋友回复确认(SYN-ACK),你再回复收到(ACK)。如果再增加一次确认(四次握手),就像朋友再发短信确认“我们真的去吗?”,这增加了不必要的沟通步骤。
- 示例:现有的三次握手已经确认双方的存在和状态,增加第四次握手只是对已确认的连接再确认一次,没有实质性可靠性提升。
延迟问题
- 解释:四次握手会导致连接建立时间增加,影响网络通信的效率。每次额外的握手步骤都需要时间,增加了延迟。
- 类比:每增加一次确认步骤,就像你和朋友确认晚饭计划的时间增加了一倍,不仅浪费时间,还可能造成不必要的等待。
- 示例:在三次握手的基础上增加第四次握手,导致连接建立时间增加,没有显著的可靠性提升,反而增加了延迟。
三次握手已经足够
- 解释:三次握手通过三步过程已经能够确保双方准备好进行通信,防止旧连接误用,同步初始序列号,并避免资源浪费。三次握手平衡了连接的可靠性和效率,已经足够确保连接的正确性。
- 类比:就像打电话确认晚饭计划,你们三次确认已经足够清楚,没必要再增加一次确认。
- 示例:三次握手通过 SYN、SYN-ACK 和 ACK 包确认双方的状态,确保连接建立和资源分配。
关键点总结:
- 增加不必要的复杂性:四次握手增加了额外的确认步骤,使连接建立过程复杂化,没有实质性提升。
- 延迟问题:四次握手导致连接建立时间增加,影响网络通信的效率。
- 三次握手已经足够:三次握手已经平衡了连接的可靠性和效率,确保双方的状态和资源分配。
最后:
欢迎大家关注我的微信公众号「跟着小康学编程」!本号致力于分享C/C++/Go/Java 语言学习、计算机基础原理、Linux 编程、数据库、微服务、容器技术 等内容。文章力求通俗易懂,并配有代码示例,方便初学者理解。如果您对这些内容感兴趣,欢迎关注我的公众号「跟着小康学编程」。
后续,我还会陆续分享各个方向的编程面试题,包括C/C++、Java、Go,以及操作系统、计算机网络、数据结构、数据库和微服务等领域,为大家的面试提供帮助。
此外,小康最近创建了一个技术交流群,专门用来讨论技术问题和解答读者的疑问。在阅读文章时,如果有不理解的知识点,欢迎大家加入交流群提问。我会尽力为大家解答。期待与大家共同进步!