TCP 三次握手和四次挥手

✏️作者:银河罐头
系列专栏:JavaEE

“种一棵树最好的时间是十年前,其次是现在”

目录

  • TCP 建立连接(三次握手)
    • 为啥不能是 4 次?
    • 为啥不能是 2 次?
    • 三次握手的意义:
  • TCP 断开连接(四次挥手)
    • 为啥是 4 次?
    • 1.CLOSE_WAIT
    • 2.TIME_WAIT

TCP 的建立连接过程(三次握手)和断开连接过程(四次挥手)

TCP 建立连接(三次握手)

通信双方各自要记录对方的信息,彼此之间要相互认同。

举个栗子:

TCP 三次握手和四次挥手_第1张图片

这个过程中的每次通信,都称为是一次"握手"(形象的比喻)

上面的例子中进行了4 次交互,但是其中有 2 次可以合并成 1 次。

TCP 三次握手和四次挥手_第2张图片

总结:所谓的三次握手,本质上是四次交互。通信双方各自向对方发起一个建立连接的请求,然后再各自向对方回应一个 ack。这里其实是有 4 次信息交互,但是其中有 2 次交互是可以合并成 1 次交互的。因此就构成了三次握手。

为啥不能是 4 次?

  • 为啥要把中间这 2 次合并?不合并行嘛?

必须合并!

封装分用 2 次一定比封装分用 1 次,成本更高。

举个栗子:

我想在淘宝上买 3 样东西

假设我是在一个淘宝店铺下单的,通过多个订单来买的,此时店家是通过 3 个快递发给我?还是 1 个快递直接发了?分 3 次发,3 次包装成本,3 次快递费;1 次发了,1 次快递成本,1 次快递费。

为啥不能是 2 次?

  • 如果是 2 次握手,能否完成建立连接的过程?

不行!(无法完全验证双方的发送和接收能力)

除了,通信双方要彼此认同之外,三次握手还有别的作用。

三次握手另外一个重要作用:验证通信双方各自的发送能力和接收能力是否正常。

三次握手也是一定程度的保证了 TCP 传输的可靠性。(起的是辅助作用)

举个例子:

张三和李四打游戏开黑,需要连麦

TCP 三次握手和四次挥手_第3张图片

第一次交互:
当李四听到"听得到嘛",
李四就知道了:
1.张三的麦克风 ok
2.李四的耳机 ok
张三知道了:
(空)
第二次交互:
当张三听到"能听到",
张三就知道了:
1.张三的耳机 ok
2.李四的麦克风 ok
建立在第一次通信的基础上,
3.张三的麦克风 ok
4.李四的耳机 ok

第三次交互:
李四听到"好了"

意味着第二次通信李四说的"能听到"张三已经接收了

李四就知道了:
1.李四的麦克风 ok

2.张三的耳机 ok

此时,双方都知道了彼此的麦克风和耳机都是 ok 的

连接,包含连接的建立,断开和维护,三次握手只是建立这个环节。

“有连接”

1.需要连接先建立好,才能进行通信

2.如果连接断开了,此时就无法进行通信了。

3.连接建立过程中,通信双方要保存好对方的信息。

有没有连接和是否确认应答 没有任何关系。

确认应答体现的是可靠传输,可靠传输和有连接是不相关的。

无连接,也可以可靠传输。eg:飞书/钉钉/企业微信,发个消息不需要建立连接,直接就能发,发个消息有个"已读"状态,这就相当于 ack

三次握手的意义:

1.让通信双方各自建立对对方的"认同"。

2.验证通信双方各自的发送能力和接收能力是否 ok.

3.在握手的过程中,双方来协调一些重要的参数。(比如 TCP 的序号不一定是从 1 开始编号的,双方协商从哪个数字开始编号)

TCP 通信过程中,有些数据通信双方要相互同步,此时就需要有这样的交互过程,恰好可以利用三次握手的机会,来完成数据的同步。

TCP 三次握手和四次挥手_第4张图片

客户端主动给服务器发起"建立连接请求",称为"syn",同步报文段

建立连接阶段,主要认识 2 个状态

1.LISTEN 服务器的状态

表示服务器已经准备就绪,随时可以有客户端来建立连接。(相当于手机开机,信号良好,随时可以有人来打电话)

2.ESTABLISHED 客户端和服务器都有的状态

连接建立完成,接下来可以进行通信了。(相当于电话打过去,对方接通了)

TCP 断开连接(四次挥手)

"挥手"和"握手"都是客户端服务器之间的数据交互。

四次挥手和三次握手非常类似。通信双方给对方发起"断开连接请求",然后再各自给对方一个回应。

TCP 三次握手和四次挥手_第5张图片

为啥是 4 次?

  • 在断开连接过程中,中间两次,通常情况下不能合并(特殊情况下可以)

两个数据发送的时机相同才能合并,不同就不能合并。

举个栗子:
我要在淘宝上买 3 样东西。
从同一个店铺买。

如果这 3 个订单是同一时间下的,此时就可以一个包裹发过来,

如果是分开下的呢?

如果是今天买了 A,过了一周买了 B,再过一个月买了 C。此时就只能分成多个包裹发货了。

三次握手的中间 2 次能够合并,是因为他俩是同一时机。具体来说,三次握手 这 3 次交互过程是纯内核完成的(应用程序感知不到,也干预不了)

服务器的系统内核收到 syn 之后,就会立即发送 ack ,也会立即发送 syn

TCP 三次握手和四次挥手_第6张图片

FIN 的发起,不是由内核控制的,而是由应用程序调用 socket 的 close 方法(或者进程退出),才会触发 FIN。

ACK 是由内核控制的,是收到 FIN 之后,立即返回 ACK

所以第 2 步的 ACK 和第 3 步的 FIN ,这两者之间就会隔了一个时间差,这个时间是长是短得看具体代码的实现。

之前写过的 TcpEchoServer 代码:

TCP 三次握手和四次挥手_第7张图片

TCP 三次握手和四次挥手_第8张图片

TCP 三次握手和四次挥手_第9张图片

TCP 三次握手和四次挥手_第10张图片

四次挥手中涉及到的 2 个重要的 TCP 状态

1.CLOSE_WAIT

出现在被动发起断开连接的一方。

建立连接一定是客户端主动发起请求;而断开连接有可能是客户端主动发起,也可能是服务器主动发起。

举个栗子:

谈恋爱追人的时候一般是男生主动。但是分手的时候可以是男生提分手也可以是女生提分手

等待关闭(等待调用 close 方法关闭 socket)

收到 FIN 并立即返回 ACK 之后状态就设置成 CLOSE_WAIT,下一步就应该轮到应用程序调用 close 完成后续的 2 次挥手。

2.TIME_WAIT

出现在主动断开连接的一方。

假设是客户端主动断开连接,当客户端收到 第 3 次 FIN 并 返回第 4 次 ACK 之后 TCP 就进入 TIME_WAIT 状态。

此时相当于 4 次挥手都挥完了。

此时这里的 TIME_WAIT 要保持 当前的 TCP 连接状态不要立刻就释放。

  • 为啥不要立即释放,为啥要以 TIME_WAIT 保留一会儿连接?

最后这个 ACK 才刚发出去,对方还没有收到呢,万一丢包了呢。

在三次握手和四次挥手的过程中也是同样存在"超时重传"的。

如果最后一个 ACK 丢包了,站在服务器的视角来看,服务器不知道是因为 ACK 丢了还是自己发的 FIN 丢了,所以统一视为 FIN 丢了,统一进行重传操作。

既然服务器可能会重传 FIN,客户端就需要针对这个重传的 FIN 进行 ACK 响应。如果刚才把连接彻底释放了这样的话 ACK 就没办法进行了。

因此使用 TIME_WAIT 状态保留一段时间,就是为了能够处理最后一个 ACK 丢包的情况,能够在收到重传的 FIN 进行 ACK 响应。

TIME_WAIT 会等,如果等了一段时间也没有收到这个重传的 FIN,此时就认为 最后一个 ACK 没丢,此时就彻底断开连接了。

  • TIME_WAIT 具体保持多长时间就真正释放呢?

约定一个时间,2 MSL

MSL 指的是互联网上,两个结点之间,数据传输消耗的最大时间。

MSL 具体是几?

通常情况下这个值是 60 s

MSL 相当于是一个经验值。按照一般的经验来说,绝大部分数据报传输的时间都不会超过 MSL

如果经历了 2 MSL 还没有收到重传的 FIN,此时就认为最后一个 ACK 成功到达了(认为对方没有重传 FIN)

TCP 三次握手和四次挥手_第11张图片

  • 是每个状态都等 2 MSL 吗?

TIME_WAIT 才是等这个时间,其他的交互过程都是跟着超时重传的时间阈值走的

你可能感兴趣的:(tcp/ip,网络,java)