TCP三次握手和四次挥手
本文最后更新于38 天前,其中的信息可能已经过时,如有错误请发送邮件到2156936367@qq.com

前言

TCP是OSI七层模型里面的传输层的一个协议,传输层就干一件事,建立端到端的连接,那什么是端到端呢?比如说,客户端到服务端就是端到端

假设我用谷歌和火狐浏览器同时登录网站,如何让数据去到指定的软件服务上,就需要用到端口号作为地址来定位了。比如客户端这里生成不同的端口号,即使同时访问http端口80也是没问题的,根据不同的源端口号来做出响应就可以了,传输层在网络层的端到端基础上实现了服务进程到服务进程的传输

其实IP地址 + 端口号Port = 套接字Socket

理解 TCP 的三次握手和四次挥手,最简单的方法是把它想象成两个人通过对讲机进行一次严谨的通话

TCP 协议之所以复杂,是因为它要保证“可靠性”:即便网络环境很差,也要确保数据不丢、不错、不乱。

TCP 是全双工通信(双方都能同时收发)。要建立可靠连接,必须确认四个点:

  1. 客户端发送能力
  2. 客户端接收能力
  3. 服务端发送能力
  4. 服务端接收能力

三次握手 (建立连接)

TCP报文里面有SYN(同步)、ACK、FIN等标识,如果设置1就是开启这些标识,如果设置为0就是关闭这些标识。

目的: 确认双方的收发能力都是正常的,并同步初始化序列号。

打电话为例

  • 客户端: “喂,你能听到我说话吗?” (第一次握手)
  • 服务端: “听到了!你能听到我说话吗?” (第二次握手)
  • 客户端: “听到了,那我们要开始正式谈话了。” (第三次握手)

详细过程:

第一次握手 (SYN=1, seq=x)

客户端发送一个 SYN 包,请求建立连接(细说就是客户端想要和服务端进行数据的同步,同步以后,也就是三次握手之后,客户端和服务端就可以互发信息)。此时客户端进入 SYN_SENT 状态。只开启SYN包是不够的,报文里面还有一个重要的字段Sequence序号(初始序列号)

来了解一下这个seq吧

在 TCP 三次握手中,那个 seq 字段的全称是 Sequence Number(序列号),你可以把它想象成“给每一段话(每一个字节)打上的页码”,它是 TCP 实现“可靠传输”的灵魂所在。在第一次握手时,客户端发送的第一个 seq 被称为 ISN (Initial Sequence Number,初始序列号)

特点:

  • 为了安全和防止网络中残留的旧连接包干扰新连接,这个数字通常是由操作系统随机生成的
  • 它是以字节为单位的计数器:TCP 会给发送的每一个字节数据都分配一个唯一的序号。

作用:

A. 确认对方收到了(可靠性)

当客户端发出 seq=x 的包时,服务端必须回一个 ack=x+1 的包。

  • 这个 ack=x+1 的意思是:“我收到了你第 x 位之前的全部信息,下次请从第 x+1 位开始发。
  • 如果客户端发了包但没收到对应的 ACK,它就知道包丢了,会触发超时重传

B. 重新排序(乱序处理)

网络传输就像寄快递,走的路不同,到达的时间也不同。

  • 假设你发了三条信息:页码 1、页码 2、页码 3。
  • 结果因为网络拥堵,页码 3 先到了,页码 1 最后才到。
  • 接收端会根据 seq 重新排列,确保你看到的信息是“123”,而不是“321”。

C. 去除重复数据(去重)

如果网络抖动,客户端以为包丢了,又重发了一遍页码 2。

  • 接收端发现:咦,页码 2 我已经收过了。
  • 于是接收端会直接丢弃这个重复的包,保证数据不会变多。

补充

如果客户端每一次发来的SYN包,服务器都要记住其序号,并且生成自己需要记住的序号,那服务器就需要挂起非常多的资源。如果有黑客借此不断发送SYN包,又不进行下一步操作,服务器就会原地奔溃,这也就是典型的DDoS攻击。因此服务器不保存自己的序列号,而是根据服务器的IP地址和端口号等私有信息进行算法的运算得到序号

第二次握手 (SYN=1, ACK=1, seq=y, ack=x+1)

服务器收到后,回复一个 SYN+ACK 包。表示:我收到你的请求了(ACK),并且我也想和你建立连接(SYN)。此时服务器进入 SYN_RCVD 状态

第三次握手 (ACK=1, seq=x+1, ack=y+1)

客户端收到服务器的包,再发一个 ACK 包(确认)。此时客户端进入 ESTABLISHED 状态,服务器收到后也进入 ESTABLISHED 状态。

三次握手中 seq 和 ack 的演变过程(通俗演示)

假设客户端随机生成的初始序列号 ISN = 100,服务端生成的 ISN = 500

  1. 第一次握手(客户端 -> 服务端)
    • 内容:SYN=1, seq=100
    • 含义:“我要建立连接,我的初始序列号是 100。”
  2. 第二次握手(服务端 -> 客户端)
    • 内容:SYN=1, ACK=1, seq=500, ack=101
    • 含义:“收到!你给我的 100 号包我拿到了,下次请发 101 号(ack=101)。另外,我的初始序列号是 500(seq=500)。”
  3. 第三次握手(客户端 -> 服务端)
    • 内容:ACK=1, seq=101, ack=501
    • 含义:“收到!你给我的 500 号包我也拿到了,下次请发 501 号(ack=501)。你看,我现在就按你的要求发 101 号包给你了(seq=101)。”

为什么要三次?两次行不行?

不行。

如果只有两次握手,会就产生两个核心问题:无法确认客户端的接收能力 以及 产生“僵尸连接”导致服务器资源浪费

想象一下,你给朋友寄了一封信(SYN):“我们见个面吧?”

  • 场景 A(正常情况): 信很快到了,朋友回信(ACK)说:“好啊!”。你们见面了。
  • 场景 B(两次握手的灾难):
    1. 你寄出的第一封信(SYN 1)在路上被邮差弄丢了,或者是堵车堵了大半年。
    2. 因为没收到回信,你以为信丢了,又寄了第二封信(SYN 2)。
    3. 这次很快,朋友收到 SYN 2,回信说“好啊”,你们见面,事情办完,各回各家。
    4. 关键点来了: 过了半年,那封堵在路上的第一封信(SYN 1)突然送到了朋友手里。
    5. 如果是两次握手:朋友收到 SYN 1,立刻回信“好啊!”,由于协议规定两次就成功,朋友(服务端)认为连接已经建立了,于是坐那儿傻等你的消息。
    6. 但此时的你(客户端)根本没想约他,你会直接无视这封莫名的回信。
    7. 结果: 朋友(服务器)白白浪费了时间和精力(系统资源),成了“僵尸连接”。

握手后就建立了连接,客户端就可以发送HTTP请求了,服务器响应内容。

四次挥手 (断开连接)

目的: 保证双方数据都传输完毕,安全地释放连接。

通俗版比喻:

  • 客户端: “我的话说完了,我要挂了。” (第一次挥手)
  • 服务端: “我知道了,等一下,我还有点话没说完。” (第二次挥手)
  • (服务端继续传完剩下的数据…)
  • 服务端: “好了,我也说完了,挂吧。” (第三次挥手)
  • 客户端: “好的,拜拜!” (第四次挥手,然后等一会儿确认对方没再说话了,才彻底关机)

详细过程:

  1. 第一次挥手 (FIN):客户端发送 FIN 包,告诉服务器:“我没有数据要发了”。此时客户端进入 FIN_WAIT_1 状态
  2. 第二次挥手 (ACK):服务器收到后,先回一个 ACK:“收到,但我还没准备好,请等我把剩下的数据发完”。此时服务器进入 CLOSE_WAIT 状态,客户端进入 FIN_WAIT_2 状态
    • 此时连接处于“半关闭”状态,客户端不再发数据,但仍能接收服务器发来的数据。
  3. 第三次挥手 (FIN):服务器数据发完了,发送 FIN 包给客户端:“我也发完了,准备断开”。此时服务器进入 LAST_ACK 状态
  4. 第四次挥手 (ACK):客户端收到后回复 ACK:“收到,再见”。此时客户端进入 TIME_WAIT 状态,服务器收到 ACK 后直接 CLOSED。客户端等待 2MSL(报文最大生存时间)后也进入 CLOSED。

常见面试细节

1. 为什么挥手要四次,而握手只要三次?

  • 握手时:服务器可以把 ACK(确认)和 SYN(同步)放在一个包里一起发过去。
  • 挥手时:客户端说要断开,服务器可能还有数据没发完。它只能先回一个 ACK 表示收到了请求,等手头活忙完了,才能发 FIN。所以 ACK 和 FIN 是分开发送的,多了一步。

2. 为什么第四次挥手后,客户端要等 2MSL 才能彻底关闭?

有两个原因:

  • 保证最后一次 ACK 到达:如果客户端发的 ACK 在路上丢了,服务器没收到,就会重发第三次的 FIN。客户端等在那,就是为了如果服务器重发了 FIN,它能再补发一个 ACK。
  • 清理残留包:防止本次连接的“过期包”留在网络中,干扰下一个使用相同端口的新连接。

3. 什么是 TIME_WAIT 状态?

这是客户端在第四次挥手后的状态。如果服务器压力很大,产生大量 TIME_WAIT,可能会导致端口被占满,无法建立新连接。


总结

这里介绍了TCP三次握手和四次挥手的详细过程,以及为什么握手要三次,挥手要四次等问题。希望这篇介绍 TCP三次握手和四次挥手 对你有帮助~

觉得有帮助可以投喂下博主哦~感谢!
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇