乐趣区

关于java:面试官问我TCP三次握手和四次挥手我真的是

候选者 面试官 你好,请问面试能够开始了吗

面试官:嗯,开始吧

面试官 明天来聊聊 TCP 吧,TCP 的各个状态还有印象吗?

候选者:还有些许印象的,要不我就来简略说下 TCP 的三次握手和四次挥手的流程吧

候选者:说完这两个流程,就能把 TCP 的状态给涵盖上了

面试官:能够吧

候选者:在说 TCP 的三次握手和四次挥手之前,我先给你画下 TCP 的头部格局呗(:

候选者:对于 TCP 三次握手和四次挥手,咱们最次要的就是关注 TCP 头部的序列号、确认号以及几个标记位(SYN/FIN/ACK/RST)

候选者:序列号:在首次建设连贯的时候,客户端和服务端都会为「本次的连贯」随机初始化一个序列号。(纵观整个 TCP 流程中,序列号能够用来解决网络包乱序的问题)

候选者:确认号:该字段示意「接收端」通知「发送端」对上一个数据包曾经胜利接管(确认号能够⽤来解决网络包失落的问题)

候选者:而标记位就很好了解啦。SYN 为 1 时,示意心愿创立连贯。ACK 为 1 时,确认号字段无效。FIN 为 1 时,示意心愿断开连接。RST 为 1 时,示意 TCP 连贯出现异常,须要断开。

候选者:上面就先从三次握手开始吧,期间我也会在三次握手中波及到的 TCP 状态也说下的。

候选者:TCP 三次握手的过程其实就是在:确认通信单方(客户端和服务端)的序列号

候选者:它的过程是这样的

候选者:在最开始的时候,客户端和服务端都处于 CLOSE 状态

候选者:服务器被动监听某个端口,处于 LISTEN 状态

候选者:客户端会随机生成出序列号(这里的序列号个别叫做 client_isn),并且把标记位设置为 SYN(意味着要连贯),而后把该报文发送给服务端

候选者:客户端发送完 SYN 报文当前,本人便进入了 SYN_SEND 状态

候选者:服务端接管到了客户端的申请之后,本人也初始化对应的序列号(这里的序列号个别叫做 server_isn)

候选者:在「确认号」字段里填上 client_isn + 1(相当于通知客户端,曾经收到了发送过去的序列号了),并且把 SYN 和 ACK 标记位都点亮(置为 1)

候选者:把该报文发送客户端,服务端的状态变成 SYN-REVD 状态

候选者:客户端收到服务端发送的报文后,就晓得服务端曾经接管到了本人的序列号(通过确认号就能够晓得),并且接管到了服务端的序列号(server_isn)

候选者:此时,客户端须要通知服务端本人曾经接管到了他发送过去的序列号,所以在「确认号」字段上填上 server_isn+1,,并且标记位 ACK 为 1

候选者:客户端在发送报文之后,进入 ESTABLISHED 状态,而服务端接管到客户端的报文之后,也进入 ESTABLISHED 状态

候选者:这就是三次握手的过程以及波及到的 TCP 状态

候选者:总结下来,就是单方都把本身的序列号发给对方,看对方能不能接管到。如果「确认能够」,那就能够失常通信。(三次握手这个过程就能够看到单方都有接管和发送的能力)

面试官 那两次握手行吗?

候选者:两次握手只能保障客户端的序列号胜利被服务端接管,而服务端是无奈确认本人的序列号是否被客户端胜利接管。所以是不行的(:

面试官 理解了,那我想问问序列号为什么是随机的?以及序列号是怎么生成的?

候选者:一方面为了安全性(随机 ISN 能防止非同一网络的攻打),另一方面能够让通信单方可能依据序号将「不属于」本连贯的报文段抛弃

候选者:序列号怎么生成的?这…轻易猜下就应该跟「时钟」和 TCP 头部的某些属性做运算生成的吧,相似于雪花算法(:具体我忘了。

面试官 既然网络是不牢靠的,那建设连贯不是会通过三次握手吗?那要是在中途丢了,怎么办?

候选者:假如第一个包丢了,客户端发送给服务端的 SYN 包丢了(简而要之就是服务端没接管到客户端的 SYN 包)

候选者:客户端迟迟收不到服务端的 ACK 包,那会周期性超时重传,直到收到服务端的 ACK

候选者:假如第二个包丢了,服务端发送的 SYN+ACK 包丢了(简而要之就是客户端没接管到服务端的 SYN+ACK 包)

候选者:服务端迟迟收不到客户端的 ACK 包,那会周期性超时重传,直到收到客户端的 ACK

候选者:假如第三个包丢了(ACK 包),客户端发送完第三个包后单方面进入了 ESTABLISHED 状态,而服务端也认为此时连贯是失常的,但第三个包没达到服务端

候选者:一、如果此时客户端与服务端都还没数据发送,那服务端会认为本人发送的 SYN+ACK 的包没发送至客户端,所以会超时重传本人的 SYN+ACK 包

候选者:二、如果这时候客户端曾经要发送数据了,服务端接管到了 ACK + Data 数据包,那天然就切换到 ESTABLISHED 状态下,并且接管客户端的 Data 数据包

候选者:三、如果此时服务端要发送数据了,但发送不了,会始终周期性超时重传 SYN + ACK,直到接管到客户端的 ACK 包

面试官 嗯,是不是要讲下四次挥手了?

候选者:嗯,在建设完连贯之后,客户端和服务端单方都处于 ESTABLISHED 状态状态

候选者:断开连接单方都有权力的,上面我还是以客户端被动断开为例好啦。

候选者:客户端打算敞开连贯,会发 FIN 报文给服务端(其实就是把标记位 FIN 点亮),客户端发送完之后,就进入 FIN_WAIT_1 状态

候选者:服务端收到 FIN 报文之后,回复 ACK 报文给客户端(示意曾经收到了),服务端发送完之后,就进入 CLOSE_WAIT 状态

候选者:客户端接管到服务端的 ACK 报文,就进入了 FIN_WAIT_2 状态

候选者:这时候,服务器可能还有数据要发送给客户端,等服务端确认本人曾经没有数据返回给客户端之后,就发送 FIN 报文给客户端了,本人进入 LAST_ACK 状态

候选者:客户端收到服务端的 FIN 报文之后,回应 ACK 报文,本人进入 TIME_WAIT 状态

候选者:服务端收到客户端的 ACK 报文之后,服务端就进入 CLOSE 状态

候选者:客户端在 TIME_WAIT 等到 2MSL,也进入了 CLOSE 状态

候选者:四次挥手的流程到这里就完结了,联合三次握手,TCP 的各个状态也曾经说完了。

面试官:嗯嗯,刚聊完四次挥手嘛,那你感觉为什么是四次呢?

候选者:其实很好了解,当客户端第一次发送 FIN 报文之后,只是代表着客户端不再发送数据给服务端,但此时客户端还是有接收数据的能力的。而服务端收到 FIN 报文的时候,可能还有数据要传输给客户端,所以只能先回复 ACK 给客户端

候选者:等到服务端不再有数据发送给客户端时,才发送 FIN 报文给客户端,示意能够敞开了。

候选者:所以,一来一回就四次了。

面试官 从四次挥手的流程上来看,有个 TIME_WAIT 状态,你晓得这个状态干什么用的吗?(期待 2MSL)

候选者:次要有两个起因吧。1. 保障最初的 ACK 报文「接管方」肯定能收到(如果收不到,对方会 重发 FIN 报文)2. 确保在创立新连贯时,先前网络中残余的数据都失落了

候选者:其实也比拟好了解的。就正如咱们重启服务器一样,会先优雅敞开各种资源,再留有一段时间,心愿在这段时间内,资源是失常敞开的,这样重启服务器(或者公布)就根本认为不会影响到线上运行了。

面试官 假如 TIME_WAIT 状态多过会有什么危害?怎么解决呢?

候选者:从流程上看,TIME_WAIT 状态 只会呈现在 被动发动 敞开连贯的一方。危害就是会占用内存资源和端口呗(毕竟在期待嘛),解决的话,有 Linux 参数能够设置,具体忘了额。

面试官 :明天最初再问个问题吧, 咱们常说 TCP 连贯,那这个连贯到底是什么?你是怎么了解的?

候选者:其实从三次握手能够发现的是,TCP 建设连贯无非就是替换了单方的状态(比方序列号)。而后就没有而后了…连贯实质上「只是相互维持一个状态,有连贯个性」

面试官:好吧。

关注我的微信公众号【Java3y】来聊点不一样的!

【对线面试官 + 从零编写 Java 我的项目】继续高强度更新中!求 star!!

原创不易!!求三连!!

退出移动版