【HTTP】三次握手、四次挥手到底在干嘛

183 阅读5分钟

三次握手过程

恋爱模拟例子

以谈恋爱为例,两个人能够在一起最重要的事情是首先确认各自被爱的能力。接下来我们以此来模拟三次握手的过程。

第一次:
男: 我爱你
女方收到。

由此证明男方拥有的能力。

第二次:
女: 我收到了你的,我也爱你
男方收到。

OK,现在的情况说明,女方拥有被爱的能力。

第三次:
男: 我收到了你的爱
女方收到。

现在能够保证男方具备被爱的能力。

由此完整地确认了双方被爱的能力,两人开始一段甜蜜的爱情。(真不错啊~)

真实握手

其实三次握手与上面的例子非常相识,目的就是确认客户端与服务器的发送和接受能力。

三次握手的过程:

image.png

最开始双方都处于 CLOSED 状态。然后服务端开始监听某个端口,进入了LISTEN 状态。

第一次:客户端主动发起连接,发送 SYN , 变成了 SYN-SENT 状态。

第二次:服务端接收到,并返回SYN和ACK来响应客户端发来的SYN,自己变成了 SYN-REVD

第三次:客户端再发送ACK给服务端,自己变成了 ESTABLISHED 状态;服务端收到 ACK之后,也变成了ESTABLISHED 状态。

为什么是三次?

  • 为什么不是两次? 三次握手的目的是为了确认客户端与服务端的发送和接受能力,而两次无法确认客户端的接受能力。
  • 为什么不是四次? 可以是四次,但没必要。

三次握手可以携带数据吗?

第三次握手的时候,可以携带。前两次握手不能携带数据。

如果前两次握手能够携带数据,那么一旦有人想攻击服务器,那么他只需要在第一次握手中的 SYN 报文 中放大量数据,那么服务器势必会消耗更多的时间和内存空间去处理这些数据,增大了服务器被攻击的风险。

第三次握手的时候,客户端已经处于 ESTABLISHED 状态,并且已经能够确认服务器的接收、发送能力正常,这个时候相对安全了,可以携带数据。

四次挥手

过程:

image.png

刚开始双方处于 ESTABLISHED 状态。

第一次:客户端要断开了,像服务端发送FIN报文,客户端变成FIN-WAIT-1状态。

第二次:服务端接受后向客户端发送ACK报文,变成CLOSEED-WAIT状态,客户端接受到了服务器的确认,变成FIN-WAIT2状态

第三次:服务端向客户端发送FIN+ACK报文,进入LAST-ACK状态

第四次:客户端收到服务器发来的FIN+ACK后,自己变成了TIME-WAIT状态,然后发送ACK给服务端。

此时,客户端需要等待2个MSL(报文最大生存时间),在这段时间内如果客户端没有收到服务端的重发请求,那么表示ACK成功到达,挥手结束,否则客户端重发ACK。

等待2MSL的意义(为什么)

  • 不等待会怎样? 客户端发送的ACK报文段可能会丢失,若客户端不等待2MSL时间,则无法收到服务器重传的FIN+ACK报文段,所以就不会重传ACK报文,则服务端将无法进入CLOSED状态。
  • 意义 1、保证客户端发送的最后一个ACK报文段能够到达服务器。这个ACK报文段有可能会丢失,使得处于WAIT-ACK状态的服务端接收不到对已发送的FIN+ACK的确认,服务端超时重传FIN+ACK报文,而客户端能在2MSL时间内收到这个重传的FIN+ACK报文,从而重新发送ACK报文,重新启动2MSL计时器,最后客户端和服务端都进入CLOSED状态。

2、防止‘已失效的链接报文段’出现在本链接中。若客户端直接跑路,当服务端还有很多数据包要给客户端发,且还在路上的时候,此时客户端的端口此时刚好被新的应用占用,那么就接收到了无用数据包,造成数据包混乱。所以,最保险的做法是等服务器发来的数据包都死翘翘再启动新的应用。 

为什么是四次挥手而不是三次?

  • 原因 关闭连接时,当服务器收到客户端发送的FIN报文时,很可能并不会立即关闭SOCKET,所以先回复一个ACK报文。只有等到服务器所有的报文都发送完了,才能发送FIN报文,因此不能一起发送。故需要四次挥手。
  • 为什么不是三次握手 如果为三次握手,则客户端发送FIN报文后,服务端长时间的延迟可能会导致客户端误以为服务端没有收到FIN报文,从而不断重新发送FIN。

半连接队列和SYN FLood攻击的关系

三次握手前,服务端的状态从CLOSED变成LISTEN,同时在内部创建两个队列:半连接和全连接

半连接队列

当客户端发送SYN到服务端,服务端收到后回复ACK和SYN,状态由LISTEN变成SYN_RCVD,此时这个链接就被推入半链接队列。

全连接队列

当客户端返回ACK,服务端接受后,三次握手完成。这个时候连接被推入另一个TCP维护的队列,也就是全连接队列。

SYN Flood 攻击原理

SYN Flood 属于典型的 DoS/DDoS 攻击。其攻击的原理很简单,就是用客户端在短时间内伪造大量不存在的 IP 地址,并向服务端疯狂发送 SYN 。对于服务端而言,会产生两个危险的后果:

1)处理大量的 SYN 包并返回对应 ACK , 势必有大量连接处于 SYN_RCVD 状态,从而占满整个半连接队列,无法处理正常的请求。

2)由于是不存在的 IP,服务端长时间收不到客户端的 ACK ,会导致服务端不断重发数据,直到耗尽服务端的资源。

总结

本文仅为自己准备面试时对三次握手与四次挥手的一些理解。