TCP的三次握手和四次挥手详解
本文最后更新于:January 31, 2022 am
TCP
基本特点
面向连接的可靠字节流服务。
建立连接——三次握手
TCP建立连接时,需要经历下图所示的三次握手过程。
每一次握手都可以反映出不同的信息。
第一次握手
SYN标志提示TCP连接的服务端检查序列编号(seq),该序列编号为TCP连接初始端(一般是客户端)的初始序列编号。客户端通过SYN=1来告诉服务端它想要建立连接。SYN=1的报文段不携带数据,但是也要消耗一个序号。
seq是基于时钟生成一个序号,每4微秒加1,到2^32-1时又从0开始。tcp提供全双工服务,客户端和服务端都有各自的序号。编号是为了解决网络包乱序的问题。
第一次握手成功后,服务器可以知道客户端的发送能力是正常的,服务器自己的接收能力是正常的。
第二次握手
服务端用SYN=1和ACK=1来表示这条数据报是针对之前的连接请求的应答。
ack=m+1表示服务端已经收到了到m为止的报文,期待的下一个报文是m+1。
第二次握手成功后,客户端知道了服务端的接收和发送能力正常,客户端自己的接收和发送能力是正常的。
第三次握手
客户端发送确认包(ACK=1)进行应答,ack=n+1表示n为止的序号都收到了,下一次希望收到序号是n+1的报文。
seq=m+1表示当前序号时m+1,需要注意的是,ACK报文段可以携带数据,但是如果不携带数据则不消耗序号。所以下一个报文的序号还是m+1。
服务端检查ack的值以及ACK=1,接收成功,第三次握手完成。
这时,因为收到了正确的回传,说明第二次握手的信息客户端正确接收了,所以服务端知道了客户端的接收能力是正常的,同时也说明了服务器自己的发送能力是正常的。
至此,客户端和服务端都确定了自己和对方的发送、接收都是正常了,tcp连接建立完成。
问题:建立连接为什么一定要3次握手?两次可以吗
不可以。
- 三次握手才可以阻止重复历史连接的初始化(主要原因)
- 三次握手才可以同步双方的初始序列号
- 三次握手才可以避免资源浪费
阻止历史连接
客户端连续发送多次 SYN 建立连接的报文,在网络拥堵等情况下:
- 一个「旧 SYN 报文」比「最新的 SYN 」 报文早到达了服务端;
- 那么此时服务端就会回一个
SYN + ACK
报文给客户端; - 客户端收到后可以根据自身的上下文,判断这是一个历史连接序列号过期或超时),那么客户端就会发送
RST
报文给服务端,表示中止这一次连接。
如果是两次握手,服务端在收到第一次握手时,就进入了连接状态,假设这次是历史连接,客户端判断到此次连接为历史连接,那么就会回 RST 报文来断开连接,而服务段在第一次握手的时候就进入 ESTABLISHED 状态,在向客户端发送数据前,并没有阻止掉历史连接,导致服务端建立了一个历史连接,又白白发送了数据,浪费资源。
断开连接——四次挥手
TCP 是全双工 的, 每个方向必须单独地进行关闭。断开连接时需要进行4次握手。
第一次挥手
FIN=1表示要关闭连接,seq=x是当前报文序号。这次挥手表示客户端已经没有数据要发送了,想要断开连接。客户机进入终止等待1。
第二次挥手
服务端收到第一次挥手的报文后,通知上层应用程序对方已经请求断开连接,并且回复给客户端一个ACK确认报文。服务器进入关闭等待状态,此时,服务器还可以继续发送那些尚未发送完成的数据,客户端也可以接收。客户端收到确认报文后进入终止等待2。
第三次挥手
服务器发送完所有的数据后,发送一个FIN=1的报文表示自己可以断开连接了。因为第二次挥手后,服务器有可能又发送了一些数据,所以此时的seq是一个新的序列号z。服务器进入最终确认阶段。
第四次挥手
客户端收到服务器的FIN报文后,恢复一个ACK确认报文,服务器接到这个确认报文后直接关闭连接。而客户端在发出FIN报文后先是进入时间等待状态,经过**2MSL **(两倍的报文段最大存活时间,常用值有30秒、1分钟和2分钟) 的时间后,客户端也进入关闭状态。
至此,tcp连接关闭。
问题:为什么建立连接时3次握手就可以,而关闭时需要4次?
建立连接时,服务端收到第一次握手SYN请求后可以直接回复一个SYN+ACK报文,一方面确认了自己收到了客户端的连接请求,另一方面也表明自己也同意连接。
然而,关闭连接时,服务端收到客户端的FIN报文时,可能还有数据没有发送完,服务端不能立刻停止连接,它只能先发送一个确认报文给客户端。等到服务端的数据都发完了,才能向客户端发送FIN报文。所以需要4次握手。
问题:为什么要有2MSL的时间等待?
因为网络可能不稳定,导致第4次握手的ACK报文迟迟没有被服务器收到,服务器会一直超时重传FIN报文,如何客户端已经关闭,就无法处理了。所以客户端在送出第4次挥手的报文后,会等待一段时间,这段时间内没收到FIN报文,说明服务器已经收到了确认报文,客户端就可以关闭了。至于为什么时间设置成2MSL,可以这样理解:
1、如果客户机发送的第3次挥手报文不能顺利到达服务器,那么服务器那边等待的时间不可能比MSL更长,所以在一个MSL的时间内,服务器一定会重传一个FIN报文。
2、这个FIN报文最多存活MSL的时间,也就是说客户端一定会在一个MSL的时间内收到这个报文。
上面两个步骤加在一起,客户端最多等2MSL的时间,就可以确定能否关闭连接了。
参考文章
https://segmentfault.com/a/1190000022410446
https://zhuanlan.zhihu.com/p/40013850
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!