为什么三次握手,而不是两次或者四次五次?
2019/3/4更新:
在阅读了很多技术博客后,发先大家对为什么三次握手不是两次众说纷纭;我觉得说的最好的是英文文章对TCP的解读。TCP和UDP的区别就是可靠与不可靠传输。
为了实现可靠数据传输, TCP 协议的通信双方, 都必须维护各自的一个序列号, 以标识发送出去的数据包中, 哪些是已经被对方收到的。 三次握手的过程即是通信双方相互告知序列号起始值, 并确认对方已经收到了序列号起始值的必经步骤。
在这过程中序号seq和确认号ack使用是核心。(详情请看下文)
如果只是两次握手, 至多只有连接发起方的起始序列号能被确认, 另一方选择的序列号则得不到确认。
补充:
第一次握手:A传给B包丢了的话,A会周期性重传,直到收到B的确认。
第二次握手:B回传给A的序号+确认号包,A没有收到,B会周期性重传,直到收到A的确认。
第三次握手:A发给B的包丢失
A发完包后,单方面认为TCP是连接成功了,但是B只认为TCP是活跃状态。
情况1:假设双方没有数据要发送,B会重传,知道再收到A的确认。收到之后AB确认连接成功。
情况2:A有数据发送,B收到A的数据和确认包,会认为TCP连接成功。并接收A数据。
往期:
首先要了解三次握手的具体过程:
为了建立客户端和服务端的数据连接进行TCP的三次交互
(1)第一次握手:建立连接时,client端发送给server端一个SYN包(标识位SYN=1和client的初始序列号seq=x,此时标识位ACK确认号=0,表示这是一个TCP连接请求数据报文),并进入SYN_SENT状态,等待server端确认。
(2)第二次握手:server端收到c端的发来的SYN包(即收到c端发来的连接请求),同时自己也发送一个SYN+ACK包(标识位SYN和ACK都置1,表示这是确认报文。server.seq=y,以及server对client初始序号的确认号server.ack=client.seq+1=x+1)。
(3)第三次握手:client收到server的SYN+ACK包,并向server发送一个序列号(client.seq=x+1),确认号为ack(client.ack=server.seq+1=y+1),此包发送完毕,客户端和服务器进入ESTAB_LISHED(TCP连接成功)状态,完成三次握手。
为什么是三次:如果只有两次(也就是客户端发送—服务端收到并发送—客户端收到)这个过程。假如服务端发出来的数据客户端没有收到呢(数据丢失的情况)? 客户端等待一段时间后,会重新建立连接,即重新发送连接请求。如果这个过程重复很多次,那么就会产生非常多的无效连接,占用大量资源,甚至导致服务器崩溃(也就是“SYN洪水攻击”现象)。
第三次握手,就是为了防止 因数据丢失或者数据传输延迟,导致客户端重启连接的现象。这也就防止了因服务器收到过的无效链接而占用大量资源。
为什么不是四次或五次? 对于TCP连接过程即C—>S—>C;如果是四次握手那么会产生和两次握手同样的无效化连接现象,而且比两次握手更浪费时间的资源。 那么你也就知道了为什么不五次握手,三次五次七次都可以做到确认并连接成功,为什么不用最少的时间和资源呢?
为什么四次挥手?
第一次挥手:首先,client端发送一个FIN (用来释放一个连接。FIN=1表示:此报文段的发送方的数据已经发送完毕,并要求释放运输连接),用来关闭client端到server的数据传送,然后等待server端的确认。其中终止标志位FIN=1,序列号seq=u。
第二次挥手:当server收到这个FIN后,它会发送一个ACK,确认号ack(ack=client.seq+1=u+1),序列号seq=v,确认已经收到了client端的终止请求。
第三次挥手:关闭服务器到客户端的连接,发送一个FIN给客户端,FIN=1,更新的序列号seq=w,确认号ack=u+1(和第二次挥手相同)。
第四次挥手:当client收到FIN后,并发回一个ACK报文确认已经收到,其中seq=u+1,ack=server.seq+1。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。
总结全过程:客户端第一次发送FIN后,进入终止等待状态,服务器收到客户端连接释放报文段后,就立即给客户端发送确认,服务器就进入CLOSE_WAIT状态,此时TCP服务器进程就通知高层应用进程,因而从客户端到服务器的连接就释放了。此时是“半关闭状态”,即客户端不可以发送给服务器,服务器可以发送给客户端。此时,如果服务器没有数据报发送给客户端,其应用程序就通知TCP释放连接,然后发送给客户端连接释放数据报,并等待确认。客户端发送确认后,进入TIME_WAIT状态,但是此时TCP连接还没有释放,然后经过等待计时器设置的2MSL后,才进入到CLOSED状态。
为什么连接的时候是三次握手,关闭的时候却是四次握手?
答:因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,"你发的FIN报文我收到了"。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。(原文:https://blog.csdn.net/qq_38950316/article/details/81087809)
为什么最后会有客户端等待2MSL时间?
MSL是最大报文生存时间。为了保证客户端发送的最后一个ACK报文段能够到达服务器。即最后一个确认报文可能丢失,服务器会超时重传,然后服务器发送FIN请求关闭连接,客户端发送ACK确认。一个来回是两个报文生命周期。
如果没有等待时间,发送完确认报文段就立即释放连接的话,服务器就无法重传,因此也就收不到确认,就无法按步骤进入CLOSED状态。
并且可以防止已经失效的连接请求报文出现在连接中。经过2MSL,在这个连续持续的时间内,产生的所有报文段就可以都从网络消失。