【JavaEE初阶】三次握手与四次挥手

目录

📕引言

🌴三次握手四次挥手总览

🌳三次握手(建立连接)

🚩为什么是各自给对方发送SYN

🚩三次握手的意义

📌"投石问路"

📌验证双方的接听发送能力是否正常

📌三次握手过程中,还需要协商一些必要的参数

🚩建立连接阶段涉及到的两个重要状态:

🎄四次挥手(断开连接)

🚩不可合并

🚩可以合并

🚩四次挥手中涉及到的两个重要的状态.

📌CLOSE_WAIT

📌TIME_WAIT


📕引言

建立连接:三次握手

断开连接:四次挥手

握手:发送一个不携带业务数据的数据报,不起到任何业务的作用,只是用来"打招呼"。

🌴三次握手四次挥手总览

在正常情况下,TCP要经过三次握手建立连接,四次挥手断开连接

整体过程如下:

该过程对应着很多种状态的转换

服务端状态转化

  • [CLOSED -> LISTEN] 服务器端调用listen后进入LISTEN状态,等待客户端连接;
  • [LISTEN -> SYN_RCVD] 一旦监听到连接请求(同步报文段),就将该连接放入内核等待队列中,并向客户端发送SYN确认报文。
  • [SYN_RCVD -> ESTABLISHED] 服务端一旦收到客户端的确认报文,就进入ESTABLISHED状态,可以进行读写数据了。
  • [ESTABLISHED -> CLOSE_WAIT] 当客户端主动关闭连接(调用close),服务器会收到结束报文段,服务器返回确认报文段并进入CLOSE_WAIT;
  • [CLOSE_WAIT -> LAST_ACK] 进入CLOSE_WAIT后说明服务器准备关闭连接(需要处理完之前的数据);当服务器真正调用close关闭连接时,会向客户端发送FIN,此时服务器进入LAST_ACK状态,等待最后一个ACK到来(这个ACK是客户端确认收到了FIN)
  • [LAST_ACK -> CLOSED] 服务器收到了对FIN的ACK,彻底关闭连接

客户端状态转化

  • [CLOSED -> SYN_SENT] 客户端调用connect,发送同步报文段;
  • [SYN_SENT -> ESTABLISHED] connect调用成功,则进入ESTABLISHED状态,开始读写数据;
  • [ESTABLISHED -> FIN_WAIT_1] 客户端主动调用close时,向服务器发送结束报文段,同时
  • 进入FIN_WAIT_1;
  • [FIN_WAIT_1 -> FIN_WAIT_2] 客户端收到服务器对结束报文段的确认,则进入FIN_WAIT_2,开始等待服务器的结束报文段;
  • [FIN_WAIT_2 -> TIME_WAIT] 客户端收到服务器发来的结束报文段,进入TIME_WAIT,并发出LAST_ACK;
  • [TIME_WAIT -> CLOSED] 客户端要等待一个2MSL(Max Segment Life,报文最大生存时间)的时间,才会进入CLOSED状态。

下图是TCP状态转换的一个汇总:

  • 较粗的虚线表示服务端的状态变化情况;

  • 较粗的实线表示客户端的状态变化情况;

  • CLOSED是一个假想的起始点,不是真实状态

上述只是TCP三次握手四次挥手的一个总览,接下来我将具体为大家介绍以下连接是如何建立的,又是如何断开的,以及为什么要叫三次握手四次挥手

🌳三次握手(建立连接)

建立连接就是通信双方各自保存对端的信息,具体完成过程需要经过三次网络交互。

三次握手其实就是客户端服务器三次的通信的过程

三次握手的第一次,一定是客户端先发起的。这个数据报不携带任何业务数据,也就是载荷部分是空着的,只有TCP报头部分,这个TCP报头中,其中6个标志位的SYN这一位为1(意味着它就是发起请求的数据报,叫做"同步报文")

这个SYN也就是synchronize,译为"同步",在多线程中的"同步"代表互斥,在TCP中的"同步"则是希望服务器和客户端之间,达成某种配合关系,达成某种有关联的状态。

当客户端给服务器发送SYN(我想和你建立连接),此时服务器就会给客户端回应一个应答报文(ACK),这个应答报文也只是告诉客户端说,我收到你的请求了,并不是愿意跟你建立连接,这个时候紧接着服务器就会给客户端发起一个同步报文。

当客户端收到服务器发来的请求之后,也会返回一个应答报文。

上述流程,客户端和服务器各自给对方发送SYN,在各自给对方返回一个ACK,那么我们发现,这里面有四次交互,我们不是说三次交互吗?其实中间这两次是可以合并成一次的(提升效率),都是服务区给客户端返回的数据,这返回的数据里面既是一个ACK,也是一个SYN,关键在于中间的两次交互,ACK和SYN可以合并成一个网络数据。

在六个标志位中,ACK第二位为1,SYN第五位为1,所谓合并就是让这一个TCP数据报,报头中同时把这两个bit位都设置为1.

上述就是三次握手的基本流程

🚩为什么是各自给对方发送SYN

比如有这样的场景

🚩三次握手的意义

三次握手解决了什么问题?

📌"投石问路"

在正式传输业务数据之前,先确认一下通信链路是否畅通。

📌验证双方的接听发送能力是否正常

进行三次握手,本质上就是完成上述确认过程。

这里也为大家举个例子吧,还是一对情侣,他们异地,然后他们现在要打游戏连麦,交互过程如下

  1. 男:听的我说话吗?

  2. 女:听得到,你听的到我说话吗?

  3. 男:听的到,那我们开始吧!

初始情况下双方都不知道麦克风和听筒的情况。

第一次交互,这个过程中,当女生听到男生说得话,这时候

女生:

  • 知道男生的麦(发送能力)正常,不知道男生听筒(接收能力)是否正常
  • 不知道自己麦(发送能力)是否正常,知道自己听筒(接收能力)正常

男生:

  • 不知道女生麦(发送能力)是否正常,不知道女生听筒(接收能力)是否正常
  • 不知道自己麦(发送能力)是否正常,不知道自己听筒(接受能力)是否正常

第二次交互,女生给男生回应(前提是女生听到了男生说的话 ),这时候

女生:

  • 知道男生的麦(发送能力)正常,不知道男生听筒(接收能力)是否正常
  • 不知道自己麦(发送能力)是否正常,知道自己听筒(接收能力)正常

男生:

  • 知道女生麦(发送能力)正常,知道女生听筒(接收能力)正常
  • 知道自己麦(发送能力)正常,知道自己听筒(接受能力)正常

第三次交互,男生给女声回应(前提是女生的说的话男生听见了),这时候女生收到后

女生:

  • 知道男生的麦(发送能力)正常,知道男生听筒(接收能力)正常
  • 知道自己麦(发送能力)正常,知道自己听筒(接收能力)正常

男生:

  • 知道女生麦(发送能力)正常,知道女生听筒(接收能力)正常
  • 知道自己麦(发送能力)正常,知道自己听筒(接受能力)正常

这时候他们就知道对方和自己的发送能力和接收能力都正常,就可以开始通信。

TCP的三次握手也是如此。设想一下,三次握手变成了两次握手是否可行?那当然是不行的,此时服务器这边对于"发送能力""接收能力"的认知是不完整的,需要第三次交互,把客户端掌握的完整情报告知给服务器。

📌三次握手过程中,还需要协商一些必要的参数

通信双方共同商量一下,有的参数不是单方面就能确认,需要双方共同来确认出来。

要协商的东西有很多,其中TCP通信时使用的序号,就是协商出来的。

需要往往不是从 1/0开始的,而是三次握手的时候,通信双方协商出来的一个数字,第一次连接和第二次连接,协商出来的其实序号也会不同,而且差异很大!

原因:

TCP考虑到这样一个情况,避免出现"前朝的剑,斩本朝的官"

我们想象这样一个场景:

我们建立连接之后,进行若干次通信,考虑一个极端的情况,某个数据报在网络通信过程中迷路了,走了一个非常绕远的路线(不是丢包),等到这个数据报绕了半天,终于到达服务器的时候,之前的连接已经断开了,当前是一个新的连接。

服务器收到这个数据报之后,服务器会直接丢弃!

因为新的连接对应的服务器进程,可能都不是同一个程序了,那么业务逻辑也就不一样了。当然不可行。

既然要直接丢弃,那么服务器如何区分当前收到的数据报是否是"前朝"的数据报呢??

通过序号就可以区分出来,每次建立的连接,都是从一个新的数字作为起始的序号,当前本朝的数据,序号一定是沿着我们起始序号往下的数字(不会相差很多),如果突然收到一个数据报,序号和当前的起始序号差别非常大,就可以认为这个数据报是"前朝"数据报了。

总结:

三次握手主要的意义三个方面:

  • 1.投石问路,确认通信路径是畅通的
  • 2.验证通信双方的发送能力和接收能力
  • 3.协商必要的参数,比如起始序号

经典面试题:

  • TCP为什么要三次握手??
  • TCP为啥必须要三次握手??两次行不行??四次行不行??
  • 谈谈TCP建立连接的流程!!(可画图来解释)

🚩建立连接阶段涉及到的两个重要状态:

  1. LISTEN:服务器的状态.                                                                                                        表示服务器已经准备就绪,随时可以有客户端来建立连接了.                                                    相当于手机开机信号良好,随时可以有人来打电话了.
  2.  ESTABLISHED:客户端和服务器都有.                                                                                   连接建立完成接下来就可以正常通信了.                                                                                 相当于电话拨打过去,对方接通了.

🎄四次挥手(断开连接)

具体流程:

注意:三次握手,第一次发送请求一定是客户端第一次发起,而四次挥手,则不一定,客户端和服务器都可以主动发起!

此处以客户端主动提起为例:

当前客户端要进行断开连接,什么时候会触发断开连接,当客户端代码调用 socket.close 或者客户端进程结束,这样的情况就会触发tcp的四次挥手。

一旦close,客户端就会给服务器发起一个FIN(结束报文)数据报,也就是TCP的六个标志位为1,服务器收到后立即返回ACK,返回应答报文之后,服务器也会给客户端发起FIN报文,客户端返回ACK。最终完成断开连接的过程(通信双方把对端之前保存的信息删了)。

TCP中期望达成的效果是双方互删,所以双方都要发送FIN。

那么四次挥手中间两次交互是否可以合并??

有的时候可以合并,有的时候不可以合并,常规情况下可以,特殊情况下不能。

三次握手过程中,服务器收到客户端发来的请求后,SYN 和 ACK都是内核自动控制发送的返回,返回的时机其实都是内核控制的,同一时机。

而四次挥手,当服务器收到客户端发来的FIN(假设客户端主动提出断开连接),此时服务器就会立即返回ACK,这也是由内核控制的,当我们在代码中调用close或者直接结束进程的时候,才会触发服务器给客户端发送FIN(应用程序控制的)。这两个操作不是同一时机,中间可能会隔很久。

🚩不可合并

我们查看TCP服务器和客户端的搭建中的代码:【JavaEE初阶】TCP服务器和客户端的搭建-CSDN博客

其中服务代码:

这里的close操作就是服务器触发FIN的时机,当服务器发现scanner没有next了,才会结束循环,进入close操作。什么时候会发现没有next了,客户端调用close或者客户端进程退出,也就是客户端触发FIN发送给服务器之后,此时服务器就能感知到scanner没有next了。

服务器先是感知到FIN来了,然后服务器结束循环,在执行close,很明显,感知到FIN来了,这是内核的事情,一感知到内核立即返回ACK,然后才是break结束循环,到达finally进行close。

只是当前代码比较干脆,感知到scanner没有next了(客户端发来FIN),就立即结束循环,立即close,但是如果代码很复杂,在没有next到close中间,又写了很多别的代码逻辑,指不定close什么时候执行了,甚至更极端的情况,忘记执行close了......

所以由于这两个数据报触发的时机不同,因此就难以合并。

🚩可以合并

在特殊情况下上述两个数据报可以合并。

TCP中还有一个机制,叫做"延时应答"(要返回ack,但不是马上,而是稍等一会儿)。这种情况就可以合并。"延时应答"机制后面会详细讲述。

最终,上述的合并情况,属于"特殊"情况,对一般情况是不能合并的,所以,最终还是把断开连接称为"四次挥手"。

🚩四次挥手中涉及到的两个重要的状态.

📌CLOSE_WAIT

  • 出现在被动发起断开连接的一方.
  • 等待关闭(等待调用close方法关闭socket)

注意:对于 CLOSE WAIT,一般而言,对于服务器上出现大量的 CLOSE_WAIT 状态,原因就是服务器没有正确的关闭 socket,导致四次挥手没有正确完成。这是一个 BUG。说明代码忘记调用close,或者close的调用不及时。

注意:调用close不影响服务器进程的结束!并且调用close方法不等于删除对端信息。当接收方收到FIN时立即返回ACK,且进入COLSE_WAIT状态(等待应用程序调用close),当应用程序调用close方法后,接收方给发送方发送FIN,发送方收到接收方发来的FIN之后,返回ACK,这时通信双方才会删除对端信息。

📌TIME_WAIT

  • 出现在主动发起断开连接的一方.
  • 假设是客户端主动断开连接.
  • 当客户端进入TIME_ WAIT状态的时候,相当于四次挥手已经挥完了.

TIME_WAIT会持续一段时间等待对方重传的FIN,会持续多久?

面试题:如果服务器端出现大量的TIME_WAIT,如何处理?

出现大量的TIME_WAIT,说明服务器这边触发了大量的主动断开TCP连接的操作,这个操作对于服务器来说,很可能是不科学的,一般都是由客户端主动断开连接。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值