网络基础-理解TCP三次握手,四次挥手

三次握手

正常情况下,TCP要经过三次握手建立连接,四次挥手释放连接。
这里写图片描述

三次握手过程:

  • 客户端首先发起建立连接请求,向服务器发送一个SYN希望建立连接,并消耗一个序列号。
  • 服务器收到客户端的SYN请求之后,如果能够建立连接,向客户端返回一个SYN+ACK,表示确认应答。
  • 客户端收到服务器的确认应答后,向服务器端在发送一个ACK确认应答。

以上过程其实很好理解,下面总结在三次握手过程,客户端与服务器的状态变化:

服务器端状态转化:

  • 起初,客户端与服务器都是CLOSED状态。B的TCP服务器进程先创建传输控制块TCB,准备接受客户进程的连接请求。然后服务器进程就处于LISTEN(监听)状态,等待客户的连接请求。若有,则作出响应。
  • 一旦监听到连接请求,就将该连接放入内核等待队列,状态就变化为SYN_RCVD同步接收。
  • 服务器端在接收到客户端的确认应答报文时,就进入ESTABLISHED状态。

客户端状态变化:

  • 客户端向服务器发送SYN发送同步报文段,从CLOSED状态变化为SYN_SENT同步发送状态。
  • 客户端向服务器发送ACK确认应答后,就变为了ESTABLISHED状态。
  • 双方状态都变成ESTABLISHED说明连接建立,此时就可以读写数据通信了。

为什么是三次?

为什么TCP是三次握手,就不妨来看看为什么不是2次或四次。
2次握手:客户端向服务器发送SYN希望建立连接,服务器向客户端发送SYN+ACK表示确认应答。的是如果服务器返回的ACK丢失了,那么客户端就会认为连接建立失败,因为他没有收到服务器的确认应答,但是服务器端却认为连接建立了,因为他已经收到客户端的SYN并且返回了一个ACK。这样就会造成双方认知不一致的问题。那么客户端就会重复性一直向服务器发送连接请求,服务器收到建立连接请求时,也会为该连接分配资源,创建数据结构维护。所以一旦出现上面那种情况,服务器会为它认为已经建立好的连接而消耗很多资源,但是这些都属于无效资源,那么可用有效资源就会逐渐变少。

难道三次握手就不会出现这种情况吗?

如果三次握手最后一个ACK丢失的话,服务器认为连接没有建立成功,客户端认为连接已经建立,所以它在向服务器发送请求时,服务器会做出相应,告诉客户端这个是无效连接,通过RST标志位希望重新建立连接。对服务器实际上不受影响,并不会为该无效连接消耗资源。

4次握手:如果三次握手已经足够了,也就不需要四次了。如果四次握手的话,最后一个ACK丢失,又会出现2次握手的情况,造成资源的浪费。

洪水攻击

扫描二维码关注公众号,回复: 2088423 查看本文章

SYN攻击就是Client在短时间内伪造大量不存在的IP地址,并向Server不断地发送SYN包,Server则回复确认包,并等待Client确认,由于源地址不存在,因此Server需要不断重发直至超时,这些伪造的SYN包将长时间占用未连接队列,导致正常的SYN请求因为队列满而被丢弃,从而引起网络拥塞甚至系统瘫痪。

防范SYN攻击措施:降低主机的等待时间使主机尽快的释放半连接的占用,短时间受到某IP的重复SYN则丢弃后续请求。

四次挥手

这里写图片描述

四次挥手过程:

  • 客户端向服务器发送FIN希望断开连接请求。
  • 服务器向客户端发送ACK,表示同意释放连接。
  • 服务器向客户端发送一个FIN表示希望断开连接。
  • 客户端向服务器返回一个ACK表示同意释放连接。

服务器状态变化过程:

  • 当客户端主动关闭连接,服务器会受到结束报文段,服务器返回确认报文段,进入CLOSE_WAIT状态。
  • 进入CLOSE_WAIT状态后,说明服务器准备关闭连接;当真正关闭连接时,向客户端发送FIN此时服务器进入LAST_ACK状态。
  • 服务器收到了对端发来的ACK,进入CLOSED状态。

客户端状态变化:

  • 客户端主动向服务器发送结束报文段时,进入FIN_WAIT_1状态
  • 客户端收到服务器对结束报文段的确认时,进入FIN_WAIT_2状态,并等待服务器的结束报文请求。
  • 客户端收到服务器的结束报文段,进入TIME_WAIT状态,并发出最后一个ACK。
  • 客户端等待一个2MSL的时间才会进入CLOSED状态。

为什么连接的时候是三次握手,关闭的时候却是四次握手?
答:因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,”你发的FIN报文我收到了”。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。

为什么在TIM_WAIT必须等待2MSL时间?

两个理由:
1)保证A发送的最后一个ACK报文段能够到达B。
最后一个ACK报文段有可能丢失,客户端就会认为连接已经关闭了,而服务器没有收到确认应答,会认为连接还未关闭。所以就会触发超时重传机制,服务器超时重传一个FIN,接着客户端重传一次确认,重新启动2MSL计时器,最后A和B都进入到CLOSED状态,若客户端在TIME-WAIT状态不等待一段时间,而是发送完ACK报文段后立即释放连接,则无法收到服务器重传的FIN报文段,所以不会再发送一次确认报文段,则服务器就无法正常进入到CLOSED状态。

2)防止“已失效的连接请求报文段”出现在本连接中。
客户端在发送完最后一个ACK报文段后,再经过2MSL,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失,使下一个新的连接中不会出现这种旧的连接请求报文段。

下面做个实验验证TIME_WAIT:
启动服务器程序,启动客户端程序,然后ctrl-c掉客户端。

这里写图片描述

如果将服务器ctrl-c掉,此时会发现一个问题:
这里写图片描述

服务器再启动时,就会绑定失败。
这种情况显然是不合适的。如果服务器需要处理大量客户端连接时,如果此时由服务器主动断开连接,就会出现大量的TIME_WAIT连接,所占的端口号可能就不够用了,无法处理新的连接。
如何解决TIME_WAIT状态引起的bind失败

使用setsockopt设置sock描述符的选项SO_REUSEADDR为1,表示允许创建端口号相同但IP地址不同的多个socke描述符。

猜你喜欢

转载自blog.csdn.net/mxrrr_sunshine/article/details/80362360