关于三次握手与四次挥手小结

瘦欲@ 提交于 2020-03-17 17:42:12

三次握手

过程

第一次握手:客户端给服务器发送一个 SYN 报文;
第二次握手:服务器收到 SYN 报文之后,会应答一个 SYN+ACK 报文;
第三次握手:客户端收到 SYN+ACK 报文之后,回应一个 ACK 报文;
服务器收到 ACK 报文之后,三次握手完成,建立链接。
在这里插入图片描述

作用

  1. 为了确认双方的接收与发送能力是否正常;
  2. 指定自己的初始化序列号,为后面的可靠传送做准备。

为何必须三次握手,不可两次建立连接?

  1. 第一次握手:客户端发送网络包,服务端收到了。这样服务端就能得出结论:客户端的发送能力、服务端的接收能力是正常的。
  2. 第二次握手:服务端发包,客户端收到了。这样客户端就能得出结论:服务端的接收、发送能力,客户端的接收、发送能力是正常的。不过此时服务器并不能确认客户端的接收能力是否正常。
  3. 第三次握手:客户端发包,服务端收到了。这样服务端就能得出结论:客户端的接收、发送能力正常,服务器自己的发送、接收能力也正常。

所以最少三次才可以让客户端和服务器都确认,双方的发送能力与接收能力都正常

如果少一次握手会怎样?

 如果只有两次握手,假如客户端向服务器发送了请求建立连接的报文,
 而这个报文由于网络原因在网络中滞留了,
 因此客户端收不到服务器的确认报文段,
 会重新发送一个请求报文段,而该请求报文段顺利到达服务器,
 根据假设的两次握手的机制,服务器给客户端回复了确认之后,两者就建立了连接,
 当彼此收发完数据之后就断开连接。
 而此时,刚才在网络中滞留的第一个报文段若到达服务器,
 服务器会认为是客户端的正常请求,因此发送了确认报文段。
 服务器就认为建立了连接,会一直等待客户断发送数据。
 而客户端认为我并没有发送请求报文段,并不理会服务器的确认,因此不会发送数据,
 这样就会浪费服务器的资源。
 而如果是三次握手,客户端不会给服务器的确认发送确认,
 服务器收不到确认就认为连接并没有建立,因此也不会等待客户端。

状态描述

刚开始客户端处于closed状态,服务端处于listen状态

  • 第一次:客户端发送SYN报文,并指明自己序列号ISN©(序列号为动态生成),客户端改变,处于send状态;
  • 第二次:服务端接收到SYN报文后,以自己的SYN报文回应,并指定自己的序列号ISN(s),同时将客户端的ISN©+1作为ACK的值,表示已经接收到了客户端的请求,并改变状态处于SYN_RECEIVED 状态;
  • 第三次:客户端收到服务端 SYN 报文之后,会发送一个 ACK 报文,ACK的报文也是一样把服务端的 ISN + 1 ,表示已经收到了服务端的 SYN 报文,此时客户端处于 establised 状态;
    服务端收到报文后,也处于establised 状态,双方建立连接。

ISN是否固定

  • 三次握手的一个重要功能是客户端和服务端交换ISN(Initial Sequence Number),,以便让对方知道接下来接收数据的时候如何按序列号组装数据。
  • 如果ISN是固定的,攻击者很容易猜出后续的确认号,因此 ISN 是动态生成的。

半连接队列

当客户端第一次向服务端发起请求,双方未完全建立连接,
服务端收到以后会将此请求连接放入队列,这个队列就叫做半连接队列

全连接队列

已经完成三次握手流程的请求会放入全连接队列,如果队列满了有可能会出现丢包现象。

  • tcp_abort_on_overflow 为0表示如果三次握手第三步的时候全连接队列满了那么服务端扔掉客户端发过来的ack(在服务端认为连接还没建立起来)。
  • tcp_abort_on_overflow为1表示第三步的时候如果全连接队列满了,服务端发送一个reset包给客户端,表示废掉这个握手过程和这个连接(本来在服务端这个连接就还没建立起来)。

TCP内核参数:tcp_abort_on_overflow:
当 tcp 建立连接的 3 路握手完成后,将连接置入 ESTABLISHED 状态并交付给应用程序的 backlog 队列(包含半连接队列和全连接队列)时,会检查 backlog 队列是否已满。若已满,通常行为是将连接还原至 SYN_ACK 状态,以造成 3 路握手最后的 ACK 包意外丢失假象 —— 这样在客户端等待超时后可重发 ACK —— 以再次尝试进入 ESTABLISHED 状态 —— 作为一种修复/重试机制。如果启用 tcp_abort_on_overflow 则在检查到 backlog 队列已满时,直接发 reset 包给客户端终止此连接 —— 此时客户端程序会收到 104 Connection reset by peer 错误。

数据重传问题

服务器发送完SYN-ACK包,如果未收到客户确认包,服务器进行首次重传,等待一段时间仍未收到客户确认包,进行第二次重传,如果重传次数超过系统规定的最大重传次数,系统将该连接信息从半连接队列中删除。每次重传等待的时间不一定相同,一般会是指数增长,例如间隔时间为 1s, 2s, 4s, 8s…

三次握手是否可以携带数据

  • 第三次握手可以携带数据,第一次第二次不可以携带数据,如果第一次就可以携带数据的话,攻击者可以利用第一次握手携带大量数据,并把服务端返回的SYN+ACK扔掉不进行处理,疯狂发送报文,导致服务端浪费大量时间接收,使服务端容易遭受攻击。
  • 第三次握手的时候,双方都处于ESTABLISHED 状态,所以可以携带数据。

四次挥手

过程

刚开始双方都处于ESTABLISHED 状态

  1. 第一次:想要主动关闭的一方最开始处于ESTABLISHED 状态,当想要关闭时,发送FIN报文给被动方,此时主动方处于FIN_WAIT1状态;
  2. 第二次:被动方接收到主动方的FIN 报文后,返回ACK序号,主动方接收到后,状态从FIN_WAIT1改变为FIN_WAIT2状态;
  3. 第三次:此时被动方处于CLOSE_WAIT状态,并查看是否还有数据需要传输,如果有继续传输,如果数据传输完毕,被动方发送FIN报文给主动方,主动方接收到被动方的FIN报文后,改为TIME_OUT状态;
  4. 第四次:主动方发送ACK返回给被动方,被动方收到后改为CLOSED状态,主动方在TIME_WAIT时间过后改为CLOSED状态;

如果主动方在FIN_WAIT1状态时收到了被动方的FIN+ACK,可以跳过FIN_WAIT2状态,直接改为TIME_WAIT状态。

TIME_WAIT状态
客户端发送 ACK 之后不直接关闭,而是要等一阵子才关闭。原因就是:要确保服务器是否已经收到了我们的 ACK 报文,如果没有收到的话,服务器会重新发 FIN 报文给客户端,客户端再次收到 ACK 报文之后,就知道之前的 ACK 报文丢失了,然后再次发送 ACK 报文;
TIME_WAIT 持续的时间至少是一个报文的来回时间。一般会设置一个计时,如果过了这个计时没有再次收到 FIN 报文,则代表对方成功就是 ACK 报文,此时处于 CLOSED 状态。

状态详解

LISTEN - 侦听来自远方TCP端口的连接请求;
SYN-SEND -在发送连接请求后等待匹配的连接请求;
SYN-RECEIVED - 在收到和发送一个连接请求后等待对连接请求的确认;
ESTABLISHED- 代表一个打开的连接,数据可以传送给用户;
FIN-WAIT-1 - 等待远程TCP的连接中断请求,或先前的连接中断请求的确认;
FIN-WAIT-2 - 从远程TCP等待连接中断请求;
CLOSE-WAIT - 等待从本地用户发来的连接中断请求;
CLOSING -等待远程TCP对连接中断的确认;
LAST-ACK - 等待原来发向远程TCP的连接中断请求的确认;
TIME-WAIT -等待足够的时间以确保远程TCP接收到连接中断请求的确认;
CLOSED - 没有任何连接状态;
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!