网络-----浅谈TCP的三次握手和四次挥手

TCP三次握手

TCP连接建立的过程被称为三次握手,先来看看三次握手的过程,上张图
这里写图片描述

1、客户端向服务器发出连接请求报文段,这时TCP报文段首部的同步标志位 SYN=1 ,同时选择一个初始序号 seq=x(图中seq=123)。TCP规定,SYN报文段不能携带数据但要消耗掉一个序号。这时客户端进入SYN_SENT状态——第一次握手

2、服务器收到连接请求报文段之后若同意建立连接,就向客户端发送确认。在确认报文段中应把SYN和ACK都置为1,确认号是ack=x+1(在图中也就是ack=124),同时也为自己选择一个初始序号seq=y(图中为seq=456),同样的这个报文段也不能携带数据,但同样要消耗掉一个序号。这时TCP服务器进入SYN_RCVD状态——第二次握手

3、客户端收到服务器的确认后,检查ack是否为x+1,ACK是否为1(因为服务器有时候不同意建立一个连接那么这里的ACK=0,表示无效)。如果正确就建立成功,并向服务器给出确认。确认报文段的ACK置为1,确认号ack=y+1(图中就是ack=457),这时客户端就进入ESTABLISHED状态,当服务器收到客户端的确认也进入ESTABLISHED状态。——第三次握手

至此三次握手完成,随后服务器和客户端之间就开始传输数据了。


TCP四次挥手

TCP释放连接的过程被称为四次挥手,如下图:

这里写图片描述

1、客户端的应用进程向TCP发出连接释放报文,并停止发送数据,主动关闭TCP连接。客户端把连接释放报文段首部的FIN置为1,其序号为seq=u,它等于前面已经传送过的数据的最后一个字节的序号加一。这是客户端进入FIN_WAIT1状态,等待服务器端的确认。——第一次挥手

2、服务器端收到连接释放报文后就发出确认,确认号是ack=u+1,而这个报文段自己的序号是v,等于服务器前面传送过的数据的最后一个字节的序号加一。然后服务器就进入CLOSE_WAIT状态。客户端收到服务器的确认之后就进入FIN_WAIT2状态,等待服务器发出连接释放报文段。——第二次挥手
注:TCP服务器进程这时应该通知应用层进程,从客户端到服务器这个方向的连接已经释放了,但是这时的TCP连接处于半关闭状态,即客户端已经没有数据要发送了,但是服务器发送数据,客户端还是要接收的,也就是说从服务器到客户端这个方向的连接还没有关闭

3、如果服务器没有要发送的数据了,就发出连接释放报文段,将报文段中FIN置为1。此时服务器端的序号为w(假定半关闭状态的服务器还发送了一些消息),服务器还必须重复上次已经发送过的确认号ack=u+1,这时服务器就进入LAST_ACK状态,等待客户端的确认。——第三次挥手

4、客户端在收到服务器的连接释放报文段之后必须对此发出确认。在确认报文段中将ACK置为1,确认号ack=w+1,而自己的序号为seq=u+1。然后进入TIME_WAIT状态。在经过时间等待计时器设置的时间2MSL后,客户端才进入CLOSE状态。——第四次挥手

至此四次挥手完成,连接释放。


常见问题

在了解完三次握手和四次挥手之后,来谈谈面试中在这个方面经常会遇到的问题

1、为什么不是两次握手也不是四次握手,而是三次握手呢?

我们先来想象一下两次的情况,客户端发送连接请求报文段,服务器给出确认,然后服务器认为连接已经建立好了,开始维护这个连接,给它分配相应的资源。但是如果服务器给出的确认报文丢失了,没有到达客户端。这时客户端就认为连接并没有建立好,就继续向服务器发送连接请求报文,而服务器就会以为这是一个新的连接请求,然后维护起来。假如服务器发送的确认报文一直都丢失了,那么客户端就会一直发送连接请求报文,服务器上就会充斥着大量的无效连接,造成资源的浪费。

和这种情况类似的还有一种情况,客户端第一次发送的连接请求并没有丢失,而是因为网络节点导致延迟达到服务器,服务器以为是客户端又发起的新连接,于是服务器同意连接,并向客户端发回确认,但是此时客户端根本不会理会,服务器就一直在等待客户发送数据,同样导致服务器的资源浪费。

再来想想为什么不是四次。既然我们三次握手已经可以保证连接正常建立了,那么再一次握手岂不是浪费资源。同样的四次存在着和两次一样的缺陷,可以类比两次说明。

2、三次握手就真的能保证连接正确建立吗?

同样是上面的情况,当我们最后一个报文丢失了,这时客户端会认为连接已经建立好了,而服务器由于没有收到客户端的确认就会认为连接还没有建立好,所以并不会给这个连接分配资源。而当客户想发送数据的时候也就会发现这个连接其实根本没有建立好,这样虽然最后一个报文也会丢失,但是我们将服务器处于安全的状态。

3、那么三次握手就没有任何缺陷吗?

在第二次握手之后,收到客户端的ACK之前的TCP连接属于半连接,而此时服务器处于SYN_RECV状态,当收到客户端的ACK后才是ESTABLISHED状态。如果客户端在短时间内伪造大量的不存在的地址,并向服务器不断的发送SYN包,服务器回复确认包,并等待客户端的回复;但因为那些IP是不存在的,所以服务器需要不断的重发直至超时,这些伪造的SYN包占用未连接队列,导致正常请求的SYN请求队列满而被丢弃,从而引起系统的瘫痪和拥塞。这就是SYN攻击,是一种典型的DDOS攻击,检测的方式也十分简单:即当服务器上有大量的半连接状态的源IP地址是随机的,那说明该机器遭受SYN攻击了。

4、为什么建立连接是三次,而释放连接需要四次呢?

这是因为服务器最开始是在LISTEN的状态下,收到建立连接请求的SYN报文后,把SYN和ACK放在一个报文里发送给客户端。而关闭连接时,由于TCP属于全双工工作方式,它把FIN和ACK分了两次发,也就是在客户端请求断开时,服务器可以立即中断,也可以把自己要发给客户端的数据发送完以后在发送FIN被动中断。主要是看服务器还有没有数据要发送,如果服务器也是将FIN和ACK直接一起发给客户端,那么也就是三次挥手了。

5、那个客户端要有TIME_WAIT状态?为什么等待的时间是2MSL?

先来解释一下MSL是什么。MSL叫做最长报文段寿命,客户端等待2MSL时间主要有下面两个原因。

  • 为了保证客户端发送的最后一个ACK报文段能够到达服务器。因为这个ACK报文段有可能在传送中丢失,因而使处在LAST_ACK状态的服务器收不到客户端发送的对FIN+ACK报文段的确认报文。那么服务器会超时重传这个FIN+ACK报文段,而客户端就可以在2MSL时间内收到这个重传的FIN+ACK报文段。接着客户端重传一次确认,重新启动2MSL计时器,最后客户端和服务器都进入正常的CLOSE状态。可以试想,如果客户端不等待而是在发送完确认报文之后直接关闭连接,就会导致服务器无法按照正常步骤进入CLOSE状态。
  • 防止已经失效的连接请求报文段突然又重新传到了服务器而出现错误。来考虑一种情况:客户端发出了一个报文给服务器,但是这个报文没有传给服务器也没有丢失,而是在一些网络节点滞留了,延误到连接释放以后的某个时间才到达服务器。而连接早已经关闭,等这个报文到达之后,可能已经是一个崭新的连接了。
    如果客户端在发送完最后一个ACK报文段之后,在经过时间2MSL,就可以使本连接持续时间内所产生的所有报文都从网络中消失。这样就不会出现刚刚说的那种情况了。

猜你喜欢

转载自blog.csdn.net/qq_34021920/article/details/80371002
今日推荐