三次握手&&四次挥手

三次握手和四次挥手是什么

TCP 是面向连接的协议,所以使用 TCP 前必须先建立连接,而建立连接是通过三次握手来进行的,断开连接是通过四次挥手来进行的。

建立连接:三次握手

关于下方用到的SYN ACK标志位,请点击此处了解
关于下方用到的客户端和服务器用到的各种状态,请点击此处了解
三次握手是用来建立连接的过程,确保通信的双方都准备好数据传输。以下是三次握手的步骤:

  • 一开始,客户端和服务端都处于 CLOSE 状态(即未建立连接),但服务端开启了监听,处于 LISTEN 状态
  1. 第一次握手(SYN):

    • 客户端结束 CLOSE 状态,向服务器发送一个连接请求报文,其中标志位设置为 SYN(同步),并且初始化了一个随机的序列号用于数据传输。之后客户端为 SYN_SENT 状态。
  2. 第二次握手(SYN + ACK):

    • 服务器收到客户端的连接请求,回复一个确认报文,其中设置自己的标志位为 SYN 和 ACK(确认),并且初始化了一个随机的序列号,并将客户端发来的的序列号加一,用于后续数据传输。服务器此时处于 SYN_RCVD 状态。
  3. 第三次握手(ACK):

    • 客户端收到服务器的确认报文,向服务器发送一个确认报文,其中标志位设置为 ACK。客户端确认收到服务器的连接确认,同时确认序列号。客户端进入 ESTABUSHED 状态。
    • 服务端收到客户端的应答报文后,也进入 ESTABLISHED 状态。
      在这里插入图片描述

连接已经建立,双方可以开始进行数据传输

在这里插入图片描述

终止连接:四次挥手

在数据传输完毕后,TCP 通过四次挥手来终止连接,确保数据传输的完整性。双方都可以主动断开连接,断开连接后主机中的资源将被释放。以下是四次挥手的步骤:

  1. 第一次挥手:主动关闭方(一般是客户端)发送一个FIN(Finish)报文,表示不再发送数据。此时,主动关闭方进入FIN_WAIT_1状态。
  2. 第二次挥手:被动关闭方(一般是服务器)收到第一个FIN后,发送一个ACK(Acknowledgment)报文,确认收到了关闭请求。被动关闭方进入CLOSE_WAIT状态。客户端收到ACK后进入FIN_WAIT_2状态。
  3. 第三次挥手:被动关闭方发送自己的关闭请求,也就是发送一个FIN报文。此时,被动关闭方进入LAST_ACK状态。
  4. 第四次挥手:主动关闭方收到被动关闭方的关闭请求后,发送一个ACK报文作为确认。当被动关闭方收到这个ACK后,连接正式关闭,主动关闭方进入TIME_WAIT状态。被动关闭方在收到ACK后也会进入CLOSED状态。主动关闭方2MSL后进入CLOSED状态。

在这里插入图片描述

关于3次握手的疑问

第三次握手中,如果客户端的ACK未送达服务器,会怎样?

Server端:

  • 由于Server没有收到ACK确认,因此会重发之前的SYN+ACK(默认重发五次,之后自动关闭连接进入CLOSED状态),Client收到后会重新传ACK给Server。

Client端,两种情况:

  • 在Server进行超时重发的过程中,如果Client向服务器发送数据,数据头部的ACK是为1的,所以服务器收到数据之后会读取 ACK number,进入 establish 状态
  • 在Server进入CLOSED状态之后,如果Client向服务器发送数据,服务器会以RST包应答。

为什么是3次握手呢?2,4,5可以吗?

在这里插入图片描述首先我们要清楚,建立连接意味着OS需要把这些已经建立好的连接管理起来。要管理!就要先描述,在组织! OS内为了管理连接就要创建数据结构 struct tcp_linki{...}
所以说,创建维护连接是有成本的! ! !即 内存+CPU

2次为什么不可以

  • 2次握手—SYN洪水,非常容易收到攻击,大量的SYN请求,导致服务器OS只要收到SYN就开始维护链接,导致内存和CPU的高负荷。
    - 如果仅 SYN - SYN/ACK,那就不能判断服务器到客户端的SYN/ACK是否丢失,从而导致服务器处于一直处于ESTABLISHED状态,但客户端没有成功建立连接。因为此时服务器已经认为自己建立连接了,就不会有所谓的重传了。
    - 3次
    • 保证双发连接建立的可靠性
    • 避免引入不必要的延迟和开销
    • 对网络实时性需求进行平衡考虑
  • 4次
    • 四次握手可以增加可靠性,但需要额外的RTT(从发送方发送数据到接收方,再从接收方发送确认到发送方,所花费的时间)。考虑到网络实时性需求,引入额外延迟是不可取的。三次握手已经可以满足需求。
  • 5次
    • 五次握手更加冗余,会引入更多不必要的延迟和开销。并且没有明显的技术优势。
  1. 3次握手的本质
    • 本质就是在赌最后一次握手报文不会丢失,这种情况是小概率事件,如果丢失,客户端此时是认为已经连接成功的,当直接发送数据给服务器时,服务器此时是没有正常建立连接的,所以服务器会设置RST控制位发送给客户端,进行重连。
  2. 总而言之
  • 奇数次握手必然是客户端最后发送ACK,肯定是客户端先开始维护连接,而不是服务器
  • 偶数次握手必然是服务器发送ACK,肯定是服务器先开始维护连接,这会导致安全性的降低,容易被SYN攻击
  • 如果偶数次发送ACK,则服务器可能承担大量的维护连接的成本,因为服务器最后一次发送ACK时,已经确认连接成功,OS必然会创建数据结构维护连接,与2次握手类似会发生SYN洪水,而客户端则不需要成本,因为不需要维护连接,因为客户端此时并没有确认连接。
  • 再多次了没有必要,因为TCP握手并不是用来解决安全问题的,只是为了自己不要有明显的漏洞,所以SYN洪水肯定是会存在的,越多次的握手效率越低,3次就够了,没有明显的漏洞,可以缓解SYN洪水问题,使得攻击方成本变高,因为想要建立连接必然需要客户端先维护连接。
  1. 进一步总结
    • 3次握手没有明显的设计漏洞,一旦建立连接出现异常,成本嫁接到client,server端成本较低
    • 验证双方通信信道的通畅情况——三次握手是验证全双工通信信道通畅的最小成本!

关于四次挥手的疑问

四次挥手的设计是为了确保双方都有足够的时间来处理未完全传输的数据,以及确认对方收到了关闭请求和确认。这样可以保证数据的可靠传输和连接的正常关闭。

为什么握手要三次,挥手却要四次呢?

那是因为握手的时候并没有数据传输,所以服务端的 SYN 和 ACK 报文可以合并一起发送,但是挥手的时候有数据在传输,所以 ACK 和 FIN 报文不能同时发送,需要分两步,所以会比握手多一步。

为什么客户端在第四次挥手后还会等待 2MSL?

等待 2MSL 是因为保证服务端接收到了 ACK 报文,因为网络复杂了,很有可能 ACK 报文丢失了,如果服务端没接收到 ACK 报文的话,会重新发送 FIN 报文,只有当客户端等待了 2MSL 都没有收到重发的 FIN 报文时就表示服务端是正常收到了 ACK 报文,那么这个时候客户端就可以关闭了。
TCP规定,MSL应大于最大报文段在网络中存在的时间,以确保网络中不会存在旧的重复报文段。

2MSL是多少?

MSL 是 IP 协议中的一个时间间隔,表示一个数据包在网络中的最大生存时间。在 IPv4 中,MSL 通常被设置为 2 分钟(120 秒),而在 IPv6 中可能会有所不同。其具体时间取决于实现和配置。

因此,2MSL 通常等于 4 分钟(240 秒)。

什么情况会出现三次挥手?

当被动关闭方(上图的服务端)在 TCP 挥手过程中,没有数据要发送并且开启了 TCP 延迟应答机制,那么第二和第三次挥手就会合并传输,这样就出现了三次挥手。

异常情况

进程终止

程序不是正常退出,而是像使用了kill -9 命令一样被强行中断。在OS看来,无论是正常终止还是异常终止,都是终止,无论代码是否释放资源,只要程序终止,OS都会去释放资源,也代表着会发起四次挥手。

机器重启

和进程终止的情况相同,类似于电脑关机时,OS会提示有进程在执行是否需要关闭,关机之前就会终止进程。

机器掉电/网线断开

接收端认为连接还在, 一旦接收端有写入操作, 接收端发现连接已经不在了, 就会进行reset. 即使没有写入操作, TCP自己也内置了一个保活定时器(时间比较长,可能是几十分钟,也可能是几小时), 会定期询问对方是否还在. 如果对方不在, 也会把连接释放.
另外, 应用层的某些协议, 也有一些这样的检测机制. 例如HTTP长连接中, 也会定期检测对方的状态. 例如QQ, 在QQ断线之后, 也会定期尝试重新连接。

​ 在HTTP长连接中定期检测对方状态的意义如下:

  1. 检测连接是否断开:HTTP长连接如果一直处于闲置状态,无法确定对端是否断开,需要定期检测来确认连接状态。

  2. 防止假连接:定期检测可以判断连接是否是假连接,避免无效数据传输。

  3. 异常处理:如果检测发现连接已断开,可以进行重新连接或其他异常处理。

  4. 保活机制(keepalive-内核态,属于TCP,与HTTP的keep-alive不同,HTTP的属于用户态,是长连接机制):定期发送保活数据包,防止中间设备判断为空闲连接而断开。

  5. 探测网络:检测包可以用来探测网络质量,RTT延迟,丢包率等。

  6. 节省资源:可以关闭假连接,回收资源。

  7. 重建连接:发现断开后可以立即rebuild连接,提高可靠性。

  8. 避免冗余连接:关闭不再使用的连接,避免资源占用。

建立连接过程中的状态

  1. ESTABLISHED(已建立):在正常的数据传输过程中,连接处于这个状态。双方可以互相发送和接收数据。

  2. FIN_WAIT_1(等待对方的FIN):当客户端发送了关闭请求(FIN),进入这个状态。此时客户端等待来自服务器的确认(ACK)。

  3. CLOSE_WAIT(等待关闭):当服务器收到客户端的关闭请求(FIN),服务器进入这个状态。服务器仍可以发送数据,但不再接收客户端的新数据。

  4. FIN_WAIT_2(等待对方的关闭请求):在这个状态,客户端等待服务器发送自己的关闭请求(FIN)。

  5. TIME_WAIT(等待一段时间):在完成四次挥手后,客户端和服务器都会进入这个状态。它是为了确保网络中滞留的最后一些数据包能够被正确处理和丢弃。这个状态持续一段时间后,连接将被彻底关闭,释放所有资源。该状态不一定需要对方响应,超时未响应自动进入下一状态。

  6. LAST_ACK(等待最后的ACK):在服务器发送自己的关闭请求后,进入这个状态。服务器等待来自客户端的最后一个确认(ACK),确认客户端已收到服务器的关闭请求。该状态同样不一定需要对方响应,超时未响应自动进入下一状态。

  7. CLOSED(已关闭):在TIME_WAIT状态结束后,连接最终处于关闭状态。双方的连接已经完全关闭,不再传输数据。

需要注意的是,每个状态都代表了连接关闭过程中的一个特定阶段。

注意!!!

服务器一直不关闭套接字,而客户端已发送关闭请求

客户端会发生什么?

如果服务器一直不关闭套接字,而客户端已经发送了关闭请求,那么客户端会进入到等待服务器响应的状态,也就是FIN_WAIT_2状态。在这个状态下,客户端会等待服务器发送自己的关闭请求(即发送自己的FIN标志)。

客户端在FIN_WAIT_2状态下会等待一段时间,如果服务器一直没有发送关闭请求,那么客户端可能会超时并认为服务器已经不再响应。在这种情况下,客户端可能会采取一些处理措施,例如终止连接并向应用程序报告连接异常。所以在这个过程中,客户端不会自动退出,而是会经历FIN_WAIT_1、FIN_WAIT_2和TIME_WAIT三个状态后,最终强制断开连接。

这种情况下,客户端和服务器之间的连接并没有正常关闭,而是出现了一种不符合协议规范的状态,可能会导致资源浪费或其他问题。因此,正常情况下,服务器应该在收到客户端的关闭请求后,按照协议规定的步骤发送自己的关闭请求,以确保连接可以正确地关闭并释放相关资源。

为什么会强制退出不等服务器响应呢,想想我们在使用CSDN的时候,你不想用了会等对面服务器准备好了再关网页吗,肯定不会。

服务器会发生什么?

不关闭套接字,会导致服务器一直处于close_wait状态,链接一直在被维护,套接字资源(文件描述符)泄漏导致服务器内的资源一直被占用。所以写代码要记得关文件描述符!!!

主动断开一方完成四次挥手后的动作

无论是服务器还是客户端,TCP规定主动断开的一方都会进入TIME_WAIT状态。虽然进入TIME_WAIT意味着四次挥手已经完成,但进入TIME_WAIT状态不代表就会立即释放资源,会等待一段时间。所以此时如果重启主动断开的一方的进程,我们是无法使用上一次的端口号,因为此时端口号还被上次的链接占用了。

如果服务端挂了,不能等TIME_WAIT状态需要立即重启怎么办

此时服务端是主动关闭的一方
比如双十一期间,大量用户与淘宝服务器建立连接,如果服务端突然挂掉,那就必须得立即重启,因为你要买东西,1秒成交量多少你想想,必然不能让你久等,可此时因为TIME_WAIT状态,端口被上次的连接占用了,那就必须得等该状态结束你才能重新上线。

那怎么办呢?

  • 关闭TCP连接重置:调用setsockopt()函数,可以在CLOSE时发送RST报文强制重置连接,不经过TIME_WAIT。

扩展

以下是一位大佬 [小林coding] 的文章
没有listen,是否能建立连接呢?
总结以下就是可以。不过是客户端自己连自己。
没有accept,是否能建立连接呢?
总结一下就是可以,但是没有它就无法创建套接字,进行数据通信。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值