关于java:面试官TCP-为什么要三次握手与四次分手大部分人答不上来

43次阅读

共计 5267 个字符,预计需要花费 14 分钟才能阅读完成。

作者:等不到的口琴 \
起源:cnblogs.com/Courage129/p/14324605.html

TCP 协定简介

TCP 协定是五层协定中运输层的协定,上面依赖网络层、链路层、物理层,对于一个报文想发到另一台机器 (假如是服务器) 上对等层,每一个所依赖的层都会对报文进行包装,例如 TCP 协定就依赖网络层的 IP 协定,所以发送的报文会通过如下封装:

当这个数据包达到服务器时,服务器的网络层会对 IP 相干协定内容解封装、校验,而后运输层对 TCP 层进行解封,解封波及到一系列的步骤,例如这个数据包是要干嘛?是发给我的吗? 这些操作须要依据 TCP 报文的首部信息来判断,首部蕴含以下内容:

次要通过首部信息来理解这个包是干嘛的, 对于首部信息, 这儿须要用到的几个如下:

  • ACK:TCP 协定规定,只有 ACK= 1 时无效,也规定连贯建设后所有发送的报文的 ACK 必须为 1
  • SYN(SYNchronization):在连贯建设时用来同步序号。当 SYN= 1 而 ACK= 0 时,表明这是一个连贯申请报文。对方若批准建设连贯,则应在响应报文中使 SYN= 1 和 ACK=1. 因而, SYN 置 1 就示意这是一个连贯申请或连贯承受报文。
  • FIN(finis):即完,终结的意思,用来开释一个连贯。当 FIN = 1 时,表明此报文段的发送方的数据曾经发送结束,并要求开释连贯。

「留神」·URG、ACK、PSH、PST、RST、SYN、FIN只有一位,也就是只有 0 或者 1 两种状态。

TCP 协定三次握手

「第一次握手」:客户端先向服务端发送一个申请连贯的报文段,这个报文段 SYN 位设置为 1, 序列号 Seq(Sequence Number) 设置为某一值,假如为 X,发送进来之后客户端进入 SYN_SEND 状态,期待服务器的确认;

「第二次握手」:服务器收到 SYN 报文段。服务器收到客户端的 SYN 报文段,须要对这个 SYN 报文段进行确认,设置 A cknowledgment Number 为 x +1(Sequence Number+1);同时,本人本人还要发送 SYN 申请信息,将 SYN 地位为 1,Sequence Number为 y;服务器端将上述所有信息放到一个报文段(即 SYN+ACK 报文段)中,一并发送给客户端,此时服务器进入 SYN_RECV 状态;

「第三次握手」:客户端收到服务器的 SYN+ACK 报文段。而后将 Acknowledgment Number 设置为 y +1,向服务器发送 ACK 报文段,这个报文段发送结束当前,客户端和服务器端都进入 ESTABLISHED 状态,实现 TCP 三次握手。

实现了三次握手,客户端和服务器端就能够开始传送数据。以上就是 TCP 三次握手的总体介绍。

为什么要三次握手而不是两次?

为什么非要进行三次连贯呢?两次行吗? 在谢希仁的《计算机网络》中是这样说的:

为了避免已生效的连贯申请报文段忽然又传送到了服务端,因此产生谬误。如下:

“已生效的连贯申请报文段”的产生在这样一种状况下:client收回的第一个连贯申请报文段并没有失落,而是在某个网络结点长时间的滞留了,以至延误到连贯开释当前的某个工夫才达到server。原本这是一个早已生效的报文段。但 server 收到此生效的连贯申请报文段后,就误认为是 client 再次收回的一个新的连贯申请。于是就向 client 收回确认报文段,批准建设连贯。

假如不采纳“三次握手”,那么只有 server 收回确认,新的连贯就建设了。因为当初 client 并没有收回建设连贯的申请,因而不会理会 server 的确认,也不会向 server 发送数据。但 server 却认为新的运输连贯曾经建设,并始终期待 client 发来数据。这样,server 的很多资源就白白浪费掉了。

采纳“三次握手”的方法能够避免上述景象产生。例如方才那种状况,client 不会向 server 的确认收回确认。server 因为收不到确认,就晓得 client 并没有要求建设连贯。”,避免了服务器端的始终期待而浪费资源。

第三次握手失败了怎么办?

在 tcp 三次握手中 第二次握手实现后 connect 就胜利返回了 如果第三次握手的 ack 包丢了 此时 客户端已认为连贯是胜利的, 如果没有应用层的心跳包, 客户端会始终保护这个连贯 请问如何防止这种状况?

第二次握手服务器收到 SYN 包, 而后收回 SYN+ACK 数据包确认收到并且申请建设连贯,服务器进入 SYN_RECV 状态。而这个时候第三次握手时客户端发送 ACK 给服务器失败了,服务器没方法进入 ESTABLISH 状态,这个时候必定不能传输数据的,不管客户端被动发送数据与否,服务器都会有定时器发送第二步 SYN+ACK 数据包,如果客户端再次发送 ACK 胜利,建设连贯。

如果始终不胜利,服务器必定会有超时(大略 64s)设置,超时之后会给客户端发「RTS 报文」 (连贯重置),进入 CLOSED 状态,避免 SYN 洪泛攻打,这个时候客户端应该也会敞开连贯。

「SYN 洪泛攻打:」

SYN 攻打利用的是 TCP 的三次握手机制,攻打端利用伪造的 IP 地址向被攻打端发出请求,而被攻打端收回的响应 报文将永远发送不到目的地,那么「被攻打端在期待敞开这个连贯的过程中耗费了资源」,如果有成千上万的这种连贯,主机资源将被耗尽,从而达到攻打的目标。

TCP 协定四次离别

还是这个图镇帖:

四次离别,意思是某一端(能够使客户端,也能够是服务器端)想完结会话断开连接,那么具体流程是:

「第一次离别」:主机 1,设置 序列号 Seq(Sequence Number) 确认包 ACK(Acknowledgment Number),假如 seq 为 x +2,ACK=y+1, 再将 FIN 标记位设置为 1, 向主机 2 发送 FIN 报文段;之后主机 1 进入 FIN_WAIT_1 状态;这示意主机 1 没有数据要发送给主机 2 了;

「第二次离别」:主机 2 收到了主机 1 发送的 FIN 报文段,向主机 1 回一个 ACK 报文段 (其值为接管到的 FIN 报文的 seq 值 +1);主机 1 进入FIN_WAIT_2 状态, 期待主机二的断开申请包 FIN;

「第三次离别」:主机 2 向主机 1 发送 FIN 报文段,意思是我能够断开连接了, 申请敞开连贯,同时主机 2 进入 CLOSE_WAIT 状态;

「第四次离别」:主机 1 收到主机 2 发送的 FIN 报文段,向主机 2 发送 ACK 报文段, 值为刚刚接管到的 FIN 包 Seq 值 +1,而后主机 1 进入 TIME_WAIT 状态;主机 2 收到主机 1 的 ACK 报文段当前,就敞开连贯;此时,主机 1 期待 2MSL 后仍然没有收到回复,则证实 Server 端已失常敞开,那好,主机 1 也能够敞开连贯了。

为什么要四次挥手

TCP 是全双工模式,这就意味着,当主机 1 收回 FIN 报文段时,只是示意主机 1 曾经没有数据要发送了,主机 1 通知主机 2,它的数据曾经全副发送结束了;然而,这个时候主机 1 还是能够承受来自主机 2 的数据;当主机 2 返回 ACK 报文段时,示意它曾经晓得主机 1 没有数据发送了,然而主机 2 还是能够发送数据到主机 1 的;当主机 2 也发送了 FIN 报文段时,这个时候就示意主机 2 也没有数据要发送了,就会通知主机 1,我也没有数据要发送了,之后彼此就会欢快的中断这次 TCP 连贯。如果要正确的了解四次离别的原理,就须要理解四次离别过程中的状态变动。

四次挥手状态解释

FIN_WAIT_1 : 这个状态要好好解释一下,其实 FIN_WAIT_1FIN_WAIT_2状态的真正含意都是示意期待对方的 FIN 报文。而这两种状态的区别是:FIN_WAIT_1状态实际上是当 SOCKET 在 ESTABLISHED 状态时,它想被动敞开连贯,向对方发送了 FIN 报文,此时该 SOCKET 即进入到 FIN_WAIT_1 状态。「也就是, 收回 FIN 包之后进入 FIN_WAIT_1 状态」

而当对方回应 ACK 报文后,则进入到 FIN_WAIT_2 状态,当然在理论的失常状况下,无论对方何种状况下,都应该马上回应 ACK 报文,所以 FIN_WAIT_1 状态个别是比拟难见到的,而 FIN_WAIT_2 状态还有时经常能够用 netstat 看到。「也就是, 收回 ACK 报文之后进入 FIN_WAIT_2 状态」

「被动方 FIN_WAIT_2:下面曾经具体解释了这种状态,实际上FIN_WAIT_2 状态下的 SOCKET,示意半连贯,也即有一方要求 close 连贯,但另外还通知对方,我临时还有点数据须要传送给你 (ACK 信息),稍后再敞开连贯。

「被动方 CLOSE_WAIT:这种状态的含意其实是示意在期待敞开。怎么了解呢?当对方 close 一个 SOCKET 后发送FIN 报文给本人,你零碎毫无疑问地会回应一个 ACK 报文给对方,此时则进入到 CLOSE_WAIT 状态。接下来呢,实际上你真正须要思考的事件是观察你是否还有数据发送给对方,如果没有的话,那么你也就能够 close 这个 SOCKET,发送 FIN 报文给对方,也即敞开连贯。所以你在 CLOSE_WAIT 状态下,须要实现的事件是期待你去敞开连贯。

「被动方 LAST_ACK : 这个状态还是比拟容易好了解的,它是被动敞开一方在发送FIN 报文后,最初期待对方的 ACK 报文。当收到 ACK 报文后,也即能够进入到 CLOSED 可用状态了。「也就是接管到了对方的 FIN 包, 本人收回了 ACK 以及 FIN 包之后的状态」

「被动方 TIME_WAIT : 示意收到了对方的FIN 报文,并发送出了 ACK 报文,就等 2MSL 后即可回到 CLOSED 可用状态了。如果 FIN_WAIT1 状态下,收到了对方同时带 FIN 标记和 ACK 标记的报文时,能够间接进入到 TIME_WAIT 状态,而无须通过 FIN_WAIT_2 状态。

「被动方CLOSED : 示意连贯中断。

TCP 状态图

状态图解释

  1. CLOSED:起始点,在超时或者连贯敞开时候进入此状态。
  2. LISTEN:svr 端在期待连贯过去时候的状态,svr 端为此要调用 socket,bind,listen 函数,就能进入此状态。此称为应用程序被动关上(期待客户端来连贯)。
  3. SYN_SENT: 客户端发动连贯,发送 SYN 给服务器端。如果服务器端不能连贯,则间接进入 CLOSED 状态。
  4. SYN_RCVD:跟 3 对应,服务器端承受客户端的 SYN 申请,服务器端由 LISTEN 状态进入 SYN_RCVD 状态。同时服务器端要回应一个 ACK,同时发送一个 SYN 给客户端;另外一种状况,客户端在发动 SYN 的同时接管到服务器端得 SYN 申请,客户端就会由 SYN_SENT 到 SYN_RCVD 状态。
  5. ESTABLISHED:服务器端和客户端在实现 3 次握手进入状态,阐明曾经能够开始传输数据了。以上是建设连贯时服务器端和客户端产生的状态转移阐明。相对来说比拟简单明了,如果你对三次握手比拟相熟,建设连贯时的状态转移还是很容易了解。接下来服务器端和客户端就进行数据传输。。。。,当然,外面也大有学识,就此打住,稍后再表。上面,咱们来看看连贯敞开时候的状态转移阐明,敞开须要进行 4 次单方的交互,还包含要解决一些善后工作(TIME_WAIT 状态),留神,这里被动敞开的一方或被动敞开的一方不是指特指服务器端或者客户端,是绝对于谁先发动敞开申请来说的。
  6. FIN_WAIT_1: 被动敞开的一方,由状态 5 进入此状态。具体的动作时发送 FIN 给对方。
  7. FIN_WAIT_2: 被动敞开的一方,接管到对方的 FIN ACK,进入此状态。由此不能再接管对方的数据。然而可能向对方发送数据。
  8. CLOSE_WAIT:接管到 FIN 当前,被动敞开的一方进入此状态。具体动作时接管到 FIN,同时发送 ACK。
  9. LAST_ACK:被动敞开的一方,发动敞开申请,由状态 8 进入此状态。具体动作时发送 FIN 给对方,同时在接管到 ACK 时进入 CLOSED 状态。
  10. CLOSING:两边同时发动敞开申请时,会由 FIN_WAIT_1 进入此状态。具体动作是,接管到 FIN 申请,同 时响应一个 ACK。
  11. TIME_WAIT:最纠结的状态来了。从状态图上能够看出,有 3 个状态能够转化成它,咱们一一来剖析:
a. 由 FIN_WAIT_2 进入此状态:在单方不同时发动 FIN 的状况下,被动敞开的一方在实现本身发动的敞开申请后,接管到被动敞开一方的 FIN 后进入的状态。b. 由 CLOSING 状态进入: 单方同时发动敞开,都做了发动 FIN 的申请,同时接管到了 FIN 并做了 ACK 的状况下,由 CLOSING 状态进入。c. 由 FIN_WAIT_1 状态进入:同时承受到 FIN(对方发动),ACK(自身发动的 FIN 回应),与 b 的区别在于自身发动的 FIN 回应的 ACK 先于对方的 FIN 申请达到,而 b 是 FIN 先达到。这种状况概率最小。

敞开的 4 次连贯最难了解的状态是 TIME_WAIT,存在TIME_WAIT 的 2 个理由:

  1. 牢靠地实现 TCP 全双工连贯的终止。
  2. 容许老的反复分节在网络中消失。

近期热文举荐:

1.1,000+ 道 Java 面试题及答案整顿(2022 最新版)

2. 劲爆!Java 协程要来了。。。

3.Spring Boot 2.x 教程,太全了!

4.20w 程序员红包封面,快快支付。。。

5.《Java 开发手册(嵩山版)》最新公布,速速下载!

感觉不错,别忘了顺手点赞 + 转发哦!

正文完
 0