网络上有很多关于讲解TCP的连接和断开的博客文章,有的是大话的形式太浅显了,有的又是很底层太深奥了,这里也总结一下自己的理解,若有不对之处,还请指出。


首先,从网络分层结构来说,TCP 协议是位于传输层的协议,如何分层有不同的模型,有的模型分七层,有的分五层,下面两张图先说明一下 TCP 协议所处的位置。

从图中我们可以很直观知道,TCP连接的建立是发送应用层 HTTP 数据包的前提,那么 TCP 连接的建立是需要客户机和服务机进行三次报文的通信确认才能建立的,就是我们说的三次握手。如图所示:

针对上图出现的相关 TCP 报文控制位名词有不明白的,可以参考我的另一篇博客 TCP 报文格式介绍 再来阅读。

三次握手过程

第一次握手

客户机发起第一次握手,发送 SYN 数据包,随机生成客户机的初始序号seq=client_isn,客户机进入SYN_SENT状态,此时客户机的同步标志位 SYN 置1,确认标志位 ACK 置0;

第二次握手

服务机接收到客户机的第一次请求,进行请求确认,确认通过后发起第二次握手,服务机发送SYN+ACK数据包,随机生成服务机的第一次序号seq=server_isn,并且包含服务机对客户机的初始序号的确认序号ack(服务机)= seq(客户机)+1=client_isn+1,此时服务机的同步标志位 SYN 置1,确认标志位 ACK 置1;

第三次握手

客户机收到服务机的请求回应后,即收到响应的 ACK 数据包,进行请求确认,确认通过后发起第三次握手,客户机发送 SYN +ACK数据包,并且发送确认序号ack(客户机)= seq(服务机)+1=server_isn+1,此时客户机的同步标志位 SYN 置0(同步完成),确认标志位 ACK 置1,客户机和服务机进入ESTAB_LISHED(TCP连接成功)状态,完成三次握手。

使用抓包工具 Wireshark 获得请求情况如图:

握手常见面试题

1.为什么需要三次握手,两次不可以吗?或者四次、五次可以吗?
我们来分析一种特殊情况,假设客户机请求建立连接,发给服务机SYN包等待服务器确认,服务器收到确认后,如果是两次握手,假设服务器给客户机在第二次握手时发送数据,数据从服务器发出,服务器认为连接已经建立,但在发送数据的过程中数据丢失,客户机认为连接没有建立,会进行重传。假设每次发送的数据一直在丢失,客户机一直SYN,服务器就会产生多个无效连接,占用资源,这个时候服务器可能会挂掉。这个现象就是我们听过的“SYN的洪水攻击”。

总结:第三次握手是为了防止:如果客户机迟迟没有收到服务机返回确认报文,这时会放弃连接,重新启动一条连接请求,但问题是:服务器不知道客户机没有收到,所以他会收到两个连接,浪费连接开销。如果每次都是这样,就会浪费多个连接开销。

四次挥手过程

【注意】中断连接端可以是Client端,也可以是Server端。

第一次挥手

假设客户机要中断连接请求,客户机发送一个FIN报文,用来关闭客户机到服务机的数据传送,然后等待服务器的确认。其中终止标志位FIN=1,序列号seq=client_isn,表示客户机已经没有数据要发送了,此时客户机关闭标志位FIN置1,确认标志位置0。

第二次挥手

服务机收到客户机发送的FIN报文后,它将发送一个ACK确认报文,确认序号ack为收到的序号加一,即ack=client_isn+1,表示服务机确认已经收到客户机的关闭请求,但是如果服务机还有数据没有发送完成,则不必急着关闭Socket,可以继续发送数据,所以先发送ACK确认报文,此时服务机关闭标志位置0,确认标志位置1,此时客户机进入FIN_WAIT状态,等待服务机发送FIN报文。

第三次挥手

当服务机发送完数据之后,向客户机发送FIN报文,告诉客户机已经没有数据要发送了,准备好关闭连接了。关闭服务器到客户机的连接,发送一个FIN给客户机,此时服务机的关闭标志为置1,确认标志位置0.

第四次挥手

客户机收到服务机发送的FIN报文后,就知道可以关闭连接了,此时客户机会发送ACK确认报文,并将确认序号seq设置为收到序号加一,但是可能由于网络动荡等其它原因,可能导致服务机没有收到客户机的ACK关闭确认报文,所以此时客户机发送ACK报文之后进入TIME_WAIT状态,如果服务机没有收到ACK报文响应后会再次重传FIN报文,然后客户机重传ACK报文。

当服务机收到ACK确认报文后,先将自己的连接关闭,客户机等待2MSL时间之后没有收到任何回复消息,则知道服务机已经收到ACK报文已经关闭连接了,此时客户机也关闭连接,TCP就这样关闭连接了。此时服务机和客户机关闭标志位和确认标志位都置1

挥手常见面试题

1.为什么需要2MSL时间?

首先,MSL即Maximum Segment Lifetime,就是最大报文生存时间,是任何报文在网络上的存在的最长时间,超过这个时间报文将被丢弃。《TCP/IP详解》中是这样描述的:MSL是任何报文段被丢弃前在网络内的最长时间。RFC 793中规定MSL为2分钟,实际应用中常用的是30秒、1分钟、2分钟等。

TCP的TIME_WAIT需要等待2MSL,当TCP的一端发起主动关闭,三次挥手完成后发送第四次挥手的ACK包后就进入这个状态,等待2MSL时间主要目的是:防止最后一个ACK包对方没有收到,那么对方在超时后将重发第三次握手的FIN包,主动关闭端接到重发的FIN包后可以再发一个ACK应答包。在TIME_WAIT状态时两端的端口不能使用,要等到2MSL时间结束才可以继续使用。当连接处于2MSL等待阶段时任何迟到的报文段都将被丢弃。

2.为什么是四次挥手,而不是三次或是五次、六次?

双方关闭连接要经过双方都同意。所以,首先是客服端给服务器发送FIN,要求关闭连接,服务器收到后会发送一个ACK进行确认。服务器然后再发送一个FIN,客户机发送ACK确认,并进入TIME_WAIT状态。等待2MSL后自动关闭。

总结:
(1)为了保证客户机发送的最后一个ACK报文段能够到达服务器。即最后一个确认报文可能丢失,服务器会超时重传,然后服务器发送FIN请求关闭连接,客户机发送ACK确认。一个来回是两个报文生命周期。

如果没有等待时间,发送完确认报文段就立即释放连接的话,服务器就无法重传,因此也就收不到确认,就无法按步骤进入CLOSE状态,即必须收到确认才能close。
(2)防止已经失效的连接请求报文出现在连接中。经过2MSL,在这个连续持续的时间内,产生的所有报文段就可以都从网络消失。

下面三张图分别总结了client端和serer端 TCP 连接和断开的经历过程,以及整个TCP连接的过程

完。

Q.E.D.

知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议

越努力,越幸运!