关于TCP三次握手和四次挥手!

为什么要三次握手

(1)确认双方的接受能力和发送能力正常

(2)指定自己的初始化序列号,为后续的可靠传输做准备

(3)如果是https协议,三次握手这个过程,还会进行数字证书的验证以及加密密钥的生成。

三次握手需要确认的事情

client要与server建立TCP连接,需要通过握手确认这四件事情

1.server需要确认它可以从client接收数据包;

2.client需要确认它可以从server接收数据包;

3.client需要确认一件事:server可以从client接收数据包;

4.server需要确认一件事:client可以从server接收数据包。

为什么两次不行

第一次握手 server确认自己可以接收client接收数据包

第二次握手 client确认自己可以接收、发送数据包

第三次握手 server确认client可以接收server的数据。

(1)阻止重复历史连接的初始化

在网络状况差或者复杂时,如果一个已经发送的连接请求在超时时间内没有收到确认,发送方连续发送多次建立连接的请求。想象一下,如果TCP建立连接仅有两次握手,那么双方会建立错误的连接,因为接收方接收到连接请求时并不清楚这是由于网络拥塞而早已过期的连接。

使用确认号为ack+1来由发送端判断是不是历史连接。

(2)对通信双方的初始序列号进行初始化

另一个使用三次握手的重要的原因就是通信双方都需要获得一个用于发送信息的初始化序列号,作为一个可靠的传输层协议,TCP 需要在不稳定的网络环境中构建一个可靠的传输层,网络的不确定性可能会导致数据包的缺失和顺序颠倒等问题。

使用序列号可以解决以下问题:

1.接收方可以通过序列号对重复的数据包进行去重;

2.发送方会在对应数据包未被 ACK 时进行重复发送;

3.接收方可以根据数据包的序列号对它们进行重新排序。

为什么三次

(1)防止使用 TCP 协议通信的双方建立了错误的连接;

(2)减少通信双方不必要的资源消耗;

(3)帮助通信双方获取初始化序列号,它们能够保证数据包传输的不重不丢,还能保证它们的传输顺序。

不使用两次握手和四次握手的原因是:

1.两次握手,无法避免历史错误连接的初始化,浪费接收方的资源;

2.四次握手,TCP 通信协议的设计可以让我们同时传递 ACK 和 SYN 两个控制信息,减少了通信次数,所以不需要使用更多的通信次数传输相同的信息。

四次挥手

TCP连接时是全双工通信,关闭时双方都需要进行关闭。

1、TCP 客户端发送一个FIN ,用来关闭从客户端到服务器的数据传送;

2、当服务器收到这个FIN ,它发回一个ACK ,确认序号为收到的序号加1 。一个FIN 也将占用一个序号;

3、服务器程序首先传送一个文件结束符,然后服务器关闭它的连接,发送一个FIN 到客户端;

4、客户端回复一个ACK确认给服务端。

半连接/关闭:TCP 连接的一端在结束它的发送之后还能接收到来自另一端数据的能力。

四次挥手的状态转换

Client端: ESTABLISHED---发送FIN给Server-->FIN_WAIT_1---接收到Server端的FIN对应的ACK-->FIN_WAIT_2---收到Server端发送过来的FIN消息-->FIIN_WAIT--2MSL之后会进入-->CLOSED

Server端:ESTABLISHED---接收到Client端的FIN->CLOSED_WAIT--Server端的应用程序关闭发送FIN--> LAST_ACK---收到Client对于FIN的ACK响应-->FIIN_WAIT---->CLOSED

三次挥手可以吗

如果是三次挥手,会怎么样?三次的话,被动关闭端在收到FIN消息之后,需要同时回复ACK和Server端的FIN消息。如果Server端在该连接上面并没有Pending的消息要处理,那么是可以的,如果Server端还需要等待一段时间才可以关闭另外一个方向的连接,那么这样的三次挥手就不能满足条件。

四次挥手失败怎么办

step1:Server发送给Client的最后一个FIN,Client收到了,也发了ACK给Server,但是Server并没有收到这个ACK。

step2:于是CLient复用了这个Port号,于是新建了一条连接,这里假设叫newConnection。

step3:Server在此过程中已经发送了重传的FIN给Client,Client上面刚建立完成的newConnection就会再次被关掉。

Time Wait

在TCP连接中四次挥手关闭连接时,主动关闭连接的一方(上图中时Client)会在发送最后一条ACK报文后维持一段时长2MSL(MSL指的是数据包在网络中的最大生存时间)的等待时间后才会真正关闭连接到CLOSED状态,该时间段内主动关闭方的状态为TIME_WAIT。即在TIME_WAIT状态时,定义这个连接的四元组(源/目的IP、源/目的端口)不能被使用。

为什么需要TIME_WAIT

为了实现TCP连接的可靠释放。

若Client最后一次ACK报文丢失了,会触发Server的超时重传机制,Server再次向Client发送FIN+ACK报文,如果Client在发送完最后一次ACK后立即断开连接(没有TIME_WAIT状态),则Server会收到RST=1的报文响应,表示连接建立异常,而此时并非异常,只是正常的关闭连接过程,进而导致Server端不能正常关闭连接。因此,Client必须维护2MSL的等待时间,确保在Server端第二次发送的FIN+ACK被Client正常接收,收到后Client立即发送ACK给Server,并重新启动2MSL计时器。(因为极端情况涉及两次报文传输(Client向Server的ACK,Server向Client的FIN+ACK),所以等待时间为2MSL)RFC 793中规定MSL为2分钟,实际应用中常用的是30秒,1分钟和2分钟等。所以意味着有可能导致几分钟内该ip:port 不能再次使用。

为使旧的重复数据包在网络中因过期而消失。可能存在一些数据包在传输过程中出现异常而导致严重推迟,而在它到来之前发送方已经重发了该报文,并完成其任务。如果在被推迟的报文未抵达前接收方断开了连接,随后又建立了一个与之前相同IP、Port的连接,而之前被推迟的报文在这时恰好到达,而此时此新连接非彼连接,从而会发生数据错乱,进而导致无法预知的情况。因此必须维持一段等待时间,使迟到的报文在网络中完全消失,并且在等待时间内,因为连接并未关闭,所以不能建立相同四元组的新连接,就不会出现数据错乱

Time wait过多危害

在高并发短连接的TCP服务器上,当服务器处理完请求后主动请求关闭连接,这样服务器上会有大量的连接处于TIME_WAIT状态,服务器维护每一个连接需要一个socket,也就是每个连接会占用一个文件描述符,而文件描述符的使用是有上限的,如果持续高并发,会导致一些连接失败。

避免time_wait过多

可设置套接字选项为SO_REUSEADDR,该选项的意思是,告诉操作系统,如果端口忙,但占用该端口TCP连接处于TIME_WAIT状态,并且套接字选项为SO_REUSEADDR,则该端口可被重用。如果TCP连接处于其他状态,依然返回端口被占用。该选项对服务程序重启非常有用。


版权声明:本文为Koala_Bryson原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。