计网——TCP三次握手四次挥手

一、三次握手

1.1 三次握手过程

三次握手具体过程如下:

  1. 服务端进程准备好接收来自外部的 TCP 连接,一般情况下是调用 bind、listen、socket 三个函数完成。这种打开方式被认为是被动打开(passive open)。然后服务端进程处于LISTEN状态,等待客户端连接请求

  2. 客户端通过 connect 发起主动打开(active open),向服务器发出连接请求,请求中首部同步位 SYN = 1,同时选择一个初始序号 sequence ,简写 seq = xSYN 报文段不允许携带数据,只消耗一个序号。此时,客户端进入 SYN-SEND 状态。

  3. 服务器收到客户端连接后,需要确认客户端的报文段。在确认报文段中,把 SYN 和 ACK 位都置为 1确认号是 ack = x + 1,同时也为自己选择一个初始序号 seq = y这个报文段也不能携带数据,但同样要消耗掉一个序号。此时,TCP 服务器进入 SYN-RECEIVED(同步收到) 状态。

  4. 客户端在收到服务器发出的响应后,还需要给出确认连接。确认连接中的 ACK 置为 1 ,序号为 seq = x + 1,确认号为 ack = y + 1。TCP 规定,这个报文段可以携带数据也可以不携带数据,如果不携带数据,那么下一个数据报文段的序号仍是 seq = x + 1。这时,客户端进入 ESTABLISHED (已连接) 状态

  5. 服务器收到客户的确认后,也进入 ESTABLISHED /ɪˈstæblɪʃt/ 状态。

        这是一个典型的三次握手过程,通过上面 3 个报文段就能够完成一个 TCP 连接的建立。三次握手的的目的不仅仅在于让通信双方知晓正在建立一个连接,也在于利用数据包中的选项字段来交换一些特殊信息,交换初始序列号。

        一般首个发送 SYN 报文的一方被认为是主动打开一个连接,而这一方通常也被称为客户端。而 SYN 的接收方通常被称为服务端,它用于接收这个 SYN,并发送下面的 SYN,因此这种打开方式是被动打开。

1.2 为什么时三次握手,两次或四次不可以吗?

        确认客户端和服务器收发能力正常

        我们需要首先弄明白三次握手的意义。三次握手(Three-way Handshake)其实就是指建立一个TCP连接时,需要客户端和服务器总共发送3个包。进行三次握手的主要作用就是为了确认双方的接收能力和发送能力是否正常、指定自己的初始化序列号为后面的可靠性传送做准备。实质上其实就是连接服务器指定端口,建立TCP连接,并同步连接双方的序列号和确认号,交换TCP窗口大小信息。

  • 第一次握手:客户端发送网络包,服务端收到了。 这样服务端就能得出结论:客户端的发送能力、服务端的接收能力是正常的。

  • 第二次握手:服务端发包,客户端收到了。 这样客户端就能得出结论:服务端的接收、发送能力,客户端的接收、发送能力是正常的。不过此时服务器并不能确认客户端的接收能力是否正常。

  • 第三次握手:客户端发包,服务端收到了。 这样服务端就能得出结论:客户端的接收、发送能力正常,服务器自己的发送、接收能力也正常。

        如果只有两次握手,那么客户端是知道了双方接受能力正常了,但是服务器端并不知道自己的发送和客户端的接受能力是否正常。因此,需要三次握手才能确认双方的接收与发送能力是否正常。

        防止「历史连接」初始化了连接

        试想如果是用两次握手,则会出现下面这种情况:

        如客户端发出连接请求,但因连接请求报文丢失而未收到确认,于是客户端再重传一次连接请求。后来收到了确认,建立了连接。数据传输完毕后,就释放了连接,客户端共发出了两个连接请求报文段,其中第一个丢失,第二个到达了服务端,但是第一个丢失的报文段只是在某些网络结点长时间滞留了,延误到连接释放以后的某个时间才到达服务端,此时服务端误认为客户端又发出一次新的连接请求,于是就向客户端发出确认报文段,同意建立连接,不采用三次握手,只要服务端发出确认,就建立新的连接了,此时客户端忽略服务端发来的确认,也不发送数据,则服务端一致等待客户端发送数据,浪费网络资源。在两次握手的情况下,服务端没有中间状态给客户端来阻止历史连接,导致服务端可能建立一个历史连接,造成资源浪费。

        所以需要第三次握手。当遇见网络堵塞,第一个丢失的报文段到达服务端的情况时,因为有第三次握手,客户端根据报文seq号知道是已经发送过的报文时会忽略服务器发来的第二次握手,此时tcp连接不成立,所以服务器端在经过一段时间后不会等待客户端发送数据,减少了网络资源的浪费。

        同步双方初始序列号(ISN)

        TCP 协议的通信双方, 都必须维护一个「序列号」, 序列号是可靠传输的一个关键因素,它的作用:可以去重、维护接受顺序、了解哪些已被接受

        可见,序列号在 TCP 连接中占据着非常重要的作用,所以当客户端发送携带「初始序列号」的 SYN 报文的时候,需要服务端回一个 ACK 应答报文,表示客户端的 SYN 报文已被服务端成功接收,那当服务端发送「初始序列号」给客户端的时候,依然也要得到客户端的应答回应,这样一来一回,才能确保双方的初始序列号能被可靠的同步

        为什么不是四次握手呢

        三次握手就已经理论上最少可靠连接建立,所以不需要使用更多的通信次数。

1.3 SYN Flood(SYN 泛洪攻击)

1.3.1 什么是SYN Flood

                SYN Flood是一种利用TCP协议漏洞的攻击方式,攻击者利用了TCP协议中的三次握手过程向目标主机发送大量的TCP SYN包(即连接请求包),目标主机在收到这些请求后会向攻击者发送TCP SYN-ACK包(即同步响应包),表示可以建立连接。攻击者在接收到这些响应包后不再继续通信,而是丢弃这些响应包,不发送TCP ACK包(即确认包),从而使得目标主机的连接队列中堆积大量未完成的连接请求,最终导致目标主机无法正常处理其他合法的连接请求,造成服务不可用的情况。

1.3.2 SYN Flood的基本原理

  1. 攻击者发送大量伪造的TCP连接请求,每个请求都带有SYN标志,但并不真正建立连接。
  2. 接收服务器在收到SYN请求后,会向攻击者发送一个SYN-ACK(同步-应答)响应,表示连接请求被接受。
  3. 攻击者收到SYN-ACK响应后,不会发送ACK(应答)确认,而是丢弃该连接请求,不建立真正的连接。
  4. 攻击者不断重复以上步骤,发送大量伪造的SYN请求,导致服务器不断等待ACK确认,同时消耗大量资源。
  5. 由于服务器资源被耗尽,合法的客户端连接请求无法得到响应,导致服务不可用。

1.3.3 如何抵御SYN Flood攻击

为了防止SYN Flood攻击,可以采取以下措施:

  1. 连接次数限制:限制服务器同时保持半连接状态的数量,当连接数达到上限时,新的连接请求会被丢弃。这可以防止服务器在短时间内保持大量半连接状态,从而减轻SYN Flood攻击带来的影响。连接数限制可以在操作系统级别或防火墙配置中设置。

  2. 使用SYN Cookies技术:该技术可以在TCP握手过程中使用一种特殊的加密算法生成一个cookie值,并将其发送给客户端。当客户端返回一个带有cookie值的ACK包时,目标主机可以根据cookie值来验证该连接是否合法。

  3. 过滤和限速: 使用防火墙或入侵防御系统(IDS/IPS)对流量进行过滤和限速,防止大量伪造的SYN请求进入服务器。过滤和限速可以帮助降低SYN Flood攻击的威力,将攻击流量控制在可接受的范围内。

  4. 负载均衡: 使用负载均衡设备将流量分散到多台服务器上,从而将攻击流量均匀地分散到不同的服务器上,减轻单台服务器的压力。

  5. 云端防护: 将服务器部署在云服务提供商的平台上,让云服务提供商处理大规模的SYN Flood攻击。云服务提供商通常拥有强大的基础设施和防护机制,能够有效地应对DDoS攻击。

  6. 限制并发连接: 应用程序层可以限制来自单个IP地址的并发连接数。这可以防止一个IP地址在短时间内发送大量的连接请求,减缓攻击的影响。

二、四次挥手

2.1 四次挥手过程

四次挥手具体过程如下:

  1. 客户端应用程序发出释放连接的报文段,并停止发送数据,主动关闭 TCP 连接。客户端主机发送释放连接的报文段,报文段中首部 FIN 位置为 1不包含数据序列号位 seq = u,此时客户端主机进入 FIN-WAIT-1(终止等待 1) 阶段。

  2. 服务器主机接受到客户端发出的报文段后,即发出确认应答报文,确认应答报文中 ACK = 1,生成自己的序号位 seq = v,ack = u + 1,然后服务器主机就进入 CLOSE-WAIT(关闭等待) 状态

  3. 客户端主机收到服务端主机的确认应答后,即进入 FIN-WAIT-2(终止等待2) 的状态。等待客户端发出连接释放的报文段。

  4. 这时服务端主机会发出断开连接的报文段,报文段中 ACK = 1,序列号 seq = v,ack = u + 1,在发送完断开请求的报文后,服务端主机就进入了LAST-ACK(最后确认)的阶段。

  5. 客户端收到服务端的断开连接请求后,客户端需要作出响应,客户端发出断开连接的报文段,在报文段中,ACK = 1, 序列号 seq = u + 1,因为客户端从连接开始断开后就没有再发送数据,ack = v + 1,然后进入到 TIME-WAIT(时间等待) 状态请注意,这个时候 TCP 连接还没有释放。必须经过时间等待的设置,也就是 2MSL 后,客户端才会进入 CLOSED 状态,时间 MSL 叫做最长报文段寿命(Maximum Segment Lifetime)。

  6. 服务端主要收到了客户端的断开连接确认后,就会进入 CLOSED 状态。因为服务端结束 TCP 连接时间要比客户端早,而整个连接断开过程需要发送四个报文段,因此释放连接的过程也被称为四次挥手。

        TCP 连接的任意一方都可以发起关闭操作,只不过通常情况下发起关闭连接操作一般都是客户端。然而,一些服务器比如 Web 服务器在对请求作出相应后也会发起关闭连接的操作。TCP 协议规定通过发送一个 FIN 报文来发起关闭操作。

2.2 TIME_WAIT

        通信双方建立 TCP 连接后,主动关闭连接的一方就会进入 TIME_WAIT 状态。TIME_WAIT 状态也称为 2MSL 的等待状态。在这个状态下,TCP 将会等待最大段生存期(Maximum Segment Lifetime, MSL) 时间的两倍。

这里需要解释下 MSL

        MSL 是 TCP 段期望的最大生存时间,也就是在网络中存在的最长时间。这个时间是有限制的,因为我们知道 TCP 是依靠 IP 数据段来进行传输的,IP 数据报中有 TTL 字段,这个字段决定了 IP报文 的生存时间,一般情况下,TCP 的最大生存时间是 2 分钟,不过这个数值是可以修改的,根据不同操作系统可以修改此值。

        基于此,我们来探讨 TIME_WAIT 的状态。

        当 TCP 执行一个主动关闭并发送最终的 ACK 时,TIME_WAIT 应该以 2 * 最大生存时间存在,这样就能够让 TCP 重新发送最终的 ACK 以避免出现丢失的情况。重新发送最终的 ACK 并不是因为 TCP 重传了 ACK,而是因为通信另一方重传了 FIN,客户端经常会发送 FIN,因为它需要 ACK 的响应才能够关闭连接,如果生存时间超过了 2MSL 的话,客户端就会发送 RST,使服务端出错。

        另一个影响2MSL等待状态的因素是当 TCP 处于等待状态时,通信双方将该连接(客 户端IP地址、客户端端口号、服务器IP地址、服务器端口号)定义为不可重新使用。只有当2MSL等待结束时,或一条新连接使用的初始序列号超过了连接之前的实例所使用的最高序列号时,或者允许使用时间戳选项来区分之前连接实例的报文段以避免混淆时,这条连接才能被再次使用。不幸的是,一些实现施加了更加严格的约束。在这些系统中,如果一个端口号被处于2MSL等待状态的任何通信端所用,那么该端口号将不能被再次使用。

2.2.1 TIME_WAIT状态存在的意义

  1. 确保可靠终止连接: 在TCP连接关闭时,服务器和客户端都需要发送最后一个ACK报文段作为确认,以确保连接的双向关闭。TIME_WAIT状态确保服务器和客户端都有足够的时间接收可能会在网络上滞留的最后一个ACK报文段。
  2. 处理延迟报文段: 在TCP连接关闭时,可能会出现网络中滞留的延迟报文段,这些报文段可能在关闭连接后才到达。TIME_WAIT状态允许这些延迟报文段在到达后被正确处理,避免了后续连接错误地接收到旧的数据。

2.2.2 为什么状态时间要保持2个MSL

        TIME_WAIT状态的持续时间被设置为两倍的MSL(最长报文段寿命,Maximum Segment Lifetime)主要是为了确保网络上所有与连接相关的报文段都能在网络中完全消失。在TCP连接关闭过程中,有两个方面需要考虑:

  1. 可靠地接收最后的确认: 在TCP连接关闭时,最后的ACK(确认)报文段可能会在网络中出现一些延迟,称为"孤儿"报文段。如果在连接关闭后立即释放资源,而这些延迟的报文段仍然在网络中,可能会导致后续连接错误地接收到旧的数据。TIME_WAIT状态给予足够的时间让这些延迟报文段被接收和处理,从而确保连接的可靠关闭。
  2. 消除冗余连接: 如果在TIME_WAIT状态时,客户端尝试重新建立一个新的连接,而旧连接的报文段在网络中仍然存在,服务器会拒绝该请求。这样可以消除冗余的连接,防止可能导致数据混乱的情况发生。

        MSL是指IP网络中数据包在网络上生存的最长时间。由于报文可能在网络中被延迟、复制、重传等,设置两倍的MSL作为TIME_WAIT状态持续的时间,可以确保所有与连接相关的报文段在网络中彻底消失,从而保证TCP连接的可靠性和稳定性。

        值得注意的是,实际上TCP连接可以在TIME_WAIT状态结束后被立即关闭,因为此时已经不再需要与旧连接相关的资源。但是,设置两倍的MSL是为了在网络环境不稳定或延迟较高的情况下,确保连接的可靠关闭。如果网络环境非常稳定且延迟较低,连接可以更快地关闭。

2.3 CLOSE_WAIT

        CLOSE_WAIT是TCP连接关闭过程中的一种状态,表示本地应用程序已经完成了数据的发送并关闭了发送端口,但是仍然可以接收来自远程应用程序的数据。在这种状态下,TCP连接仍然保持打开状态,直到远程应用程序也关闭了连接。

        CLOSE_WAIT状态通常由本地应用程序引起,当本地应用程序关闭了连接的发送端口,但是远程应用程序仍然需要发送一些数据或者完成一些操作时,TCP连接就会进入 CLOSE_WAIT状态。在这种状态下,本地应用程序仍然可以接收来自远程应用程序的数据,直到远程应用程序也关闭了连接。

        一旦远程应用程序关闭了连接,TCP连接就会从CLOSE_WAIT状态转移到FIN_WAIT_2状态,表示远程应用程序已经完成了数据的发送并关闭了发送端口,但是仍然可以接收来自本地应用程序的数据。在FIN_WAIT_2状态下,本地应用程序仍然可以向远程应用程序发送数据,直到本地应用程序也关闭了连接的接收端口。

        CLOSE_WAIT状态通常不会引起问题,但是如果TCP连接在CLOSE_WAIT状态下持续时间过长,可能会导致系统资源的浪费。因此,在实际应用中,应该尽可能避免TCP连接进入CLOSE_WAIT状态,例如,在关闭连接之前,可以发送一个FIN报文段(请求关闭连接)并等待远程应用程序发送一个ACK报文段(确认收到FIN报文段)后再关闭连接的接收端口。这样可以避免TCP连接进入CLOSE_WAIT状态,提高系统性能和资源利用率。

2.4 TIME_WAIT和CLOSE_WAIT的区别

        TIME_WAIT和CLOSE_WAIT是TCP连接关闭过程中的两种状态,它们有一些区别:

  • CLOSE_WAIT状态:

    • CLOSE_WAIT状态出现在服务端,表示服务端已经接收到了客户端发送的关闭连接请求(FIN报文段),但服务器还在等待应用层处理完成数据发送。也就是说,服务器已经关闭了向客户端的数据传输通道,但仍然可以接收来自客户端的数据。在CLOSE_WAIT状态下,服务器等待应用程序处理完剩余的数据后,会发送自己的关闭连接请求,进入LAST_ACK状态,最终完成四次挥手过程。

  • TIME_WAIT状态:

    • TIME_WAIT状态出现在客户端,表示客户端已经发送了关闭连接请求(FIN报文段)给服务器,并收到了服务器的确认(ACK报文段)。在TIME_WAIT状态下,客户端等待一段时间(通常等待2倍的MSL,即最长报文段寿命)后,确保网络中所有的延迟报文段都被丢弃。这样可以防止后续连接误认为是同一个连接的旧数据包。等待时间结束后,客户端进入CLOSED状态,彻底关闭连接。

总结区别:

  • CLOSE_WAIT状态是在服务器端,表示服务器等待应用层处理完数据后关闭连接,可以接收客户端发送的数据。

  • TIME_WAIT状态是在客户端,表示客户端等待一段时间后,确保网络中所有延迟的报文段都被丢弃,然后彻底关闭连接。

猜你喜欢

转载自blog.csdn.net/m0_62573214/article/details/132011808