TCP连接建立和释放过程 | 青训营笔记

262 阅读6分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 10 天

TCP连接建立和释放过程

 对于TCP协议,大家一定不陌生,在计算机网络上或者是各类网络应用程序中被频繁提及,诸如HTTP,HTTPS,FTP,SMTP,POP3,SSH等等协议都采用了TCP协议来建立可靠的连接而进行不同网络设备之间的通信需求。三次握手和四次挥手,指的就是TCP连接和释放的过程。

TCP三次握手

 为了保证客户端和服务端的可靠连接,TCP建立连接时必须进行三次会话,也叫TCP三次握手,进行三次握手的目的是为了确认双方的接收能力和发送能力是否正常。

TCP连接过程

 最开始的时候客户端和服务端都是处于CLOSED状态,服务端事先创建许多的传输控制块TCB监听客户端的连接请求,服务器进入LISTEN监听状态

 接下来进入第一次握手,客户端进程想要发送请求数据,要事先建立连接,所以客户端先创建TCB并向服务端发送连接请求报文,报文首部中同步位SYN=1,同时选择一个初始化序列号seq=x,此时TCP客户端进入了SYN-SENT同步已发送状态。****

 随后来到第二次握手,TCP服务器接收到连接请求报文后,如果同意连接,则回向客户端发出连接确认报文。连接确认报文中ACK=1,SYN=1,确认号位ack=x+1,同时也要自己初始化一个序列号seq=y,此时TCP服务器进程就进入了SYN-RECV同步收到状态

 最后是第三次握手,TCP客户端接收到TCP服务端的请求连接确认报文之后,还需要给服务端发出确认信息,以确保连接请求信息未失效。确认报文的ACK=1,ack=y+1,自己的序列号为seq=x+1,此时TCP连接建立,服务端客户端都进入ESTABLISHED已建立连接状态

为什么要进行第三次握手?前两次握手不是已经能够确认双方的接发能力了吗?

 原因:主要是为了防止客户端之前因为网络阻塞,网络不佳的原因阻塞的请求连接报文消息又传送到服务端,对此服务端无法识别该请求连接报文是否有效。所以需要进行第三次握手,交由客户端确认该请求连接报文是否有效,如果有效那么再发送一个确认报文给服务端,双方连接建立。若无效那么客户端则忽略服务端发来的报文信息,服务端没有接收到确认报文信息也无需分配系统资源建立连接。

 

TCP四次挥手

进行四次挥手的原因是为了进行优雅地关闭TCP连接。

 

 数据传输关闭后,双方都可以释放连接。不过在通常情况下,服务端不知道客户端是否还有请求,所以一般最终都是由客户端主动关闭连接。

第一次挥手客户端发出连接释放报文,并且停止发送数据。释放数报文首部FIN=1,其序列号seq=u(等于前面已经传送过来的数据最后一个字节的序号加1),此时,客户端进入FIN-WAIT-1状态****

第二次挥手, 服务端接收到连接释放报文后,发出确认报文,ACK=1,ack=u+1,并且带上自己的序列号seq=v,此时服务器就进入了CLOSE-WAIT状态。 随后服务端暂停接收该客户端发送的请求,准备关闭连接。

第三次挥手, 客户端接收到服务端的确认请求后,客户端就会进入FIN-WAIT-2状态,等待服务端发送释放连接报文,服务端将之前的请求数据都处理完毕并发送给客户端后,就向客户端发送连接释放报文,服务都进入LAST-ACK状态,等待客户端的最终确认。

 第四次挥手,客户端接收到服务端的连接释放报文后,必须发出确认,ACK=1,seq=u+1,ack=w+1,此时,客户端就进入了了TIME-WAIT状态,但此时TCP连接还未停止,必须等待2MSL(最长报文寿命)后,当客户端撤销相应的TCB后,客户端才会进入CLOSED关闭状态,服务端接收到确认报文后,会立即进入CLOSED关闭状态,服务器端接收到确认报文后,会立即进入CLOSED关闭状态,到这里TCP连接就断开了,四次挥手完成。

 

为什么在第四次挥手结束后客户端要等待2MSL?而服务端无需等待?

因为服务端已经接收到客户端发出的ACK,确认服务端的FIN,所以服务端收到消息时,就认为双方已经达成了同步:可以关闭TCP连接了,所以此时服务端可以安全地释放TCP连接所占用的内存资源,端口号。

但是客户端它是消息的发送者,它无从知晓自己的ACK消息是否传递到服务端,所以可能有两种情况:

1) 如果服务端没有收到自己的ACK,会超时重传FIN

那么客户端再次收到重传的FIN,会再次发送ACK

2) 如果服务端已经接收到自己的ACK,也不会发任何消息,包括ACK

所以无论情况1还是情况2客户端都需要等待,要取这两种等待时间的最大值,来应对最坏的情况发生,这个最坏的情况是:

Max(发送到服务端的ACK消息最大存活时间(MSL) + 服务端发送到客户端的FIN消息的最大存活时间(MSL),发送到服务端的ACK消息最大存活时间(MSL)) = 2MSL

等待2MSL之后,客户端就可以安心地释放TCP占用的资源,端口号,此时可以使用该端口号连接任何服务器。

为何一定要等待2MSL?

如果不等待2MSL,释放的端口可能会重连刚断开的服务器端口,这样依然存活在网络里的老TCP报文可能与新的TCP报文产生数据冲突,为避免这种情况,需要耐心等待网络中老的TCP连接的活跃报文失效,2MSL时间可以满足这个需求。

参考资料

javaguide.cn/cs-basics/n…