TCP四次挥手及相关问题

1、TCP四次挥手过程图

1、第一次挥手

客户端进程调用close或shutdown函数发出连接释放报文,并且停止发送数据。该报文首部中,FIN=1,其序列号为seq=u(等于前面已经传送过来的数据的最后一个字节的序号加1),此时,客户端进入FIN_WAIT_1状态

TCP规定,FIN报文段即使不携带数据,也要消耗一个序号。

2、第二次挥手

服务器收到连接释放报文,发出确认报文,该报文中ACK=1,ack=u+1,并且带上自己的序列号seq=v,此时,服务端就进入了CLOSE_WAIT状态。TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间。

客户端收到服务器的确认请求后,此时,客户端就进入FIN_WAIT_2状态,等待服务器发送连接释放报文(在这之前还需要接受服务器发送的最后的数据)

3、第三次挥手

服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,FIN=1,ack=u+1,由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为seq=w,此时,服务器就进入了LAST_ACK状态,等待客户端的确认。

4、第四次挥手

客户端收到服务器的连接释放报文后,必须发出确认,ACK=1,ack=w+1,而自己的序列号是seq=u+1,此时,客户端就进入了TIME_WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过2MSL(最长报文段寿命)的时间后,当客户端才进入CLOSED状态。

服务器只要收到了客户端发出的确认,立即进入CLOSED状态。可以看到,服务器结束TCP连接的时间要比客户端早一些。

相关问题:

1、为什么建立连接协议是三次握手,而关闭连接却是四次挥手呢? 
   这是因为服务端在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。而关闭连接时,当收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,己方也未必全部数据都发送给对方了,所以己方可以立即close,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,己方ACK和FIN一般都会分开发送。
2、为什么TIME_WAIT状态还需要等2MSL后才能返回到CLOSED状态? 
1)最后一个ACK丢失时重发FIN
这是因为虽然双方都同意关闭连接了,而且握手的4个报文也都协调和发送完毕,按理可以直接回到CLOSED状态(就好比STABLISH状态那样);但是因为我们必须要假想网络是不可靠的,你无法保证你最后发送的ACK报文会一定被对方收到,因状态下的SOCKET可能会因为超时未收到ACK报文,而重发FIN报文,所以这个TIME_WAIT状态的作用就是用来重发可能丢失的ACK报文。
(2)防止TCP处理同一条链接中旧实例的报文段
等待2MSL可以确保同一个链接的旧实例的报文段从网络中消失,也可以通过sock的-A选项来来绕开该机制,
2.4时间等待错误
当一段处于TIME_WAIT状态时,选择忽略重置报文RST请求,以避免时间等待错误,即,当前状态被重置报文段破坏而强制提前关闭链接
3、如果已经建立了连接,但是客户端突然出现故障了怎么办?
TCP还设有一个保活计时器,显然,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75分钟发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。

两端同时关闭链接
有同时打开,理所应当的也有同时关闭的场景,TCP协议也允许同时关闭。状态变化可以看到下图了,同时发送FIN包,两端同时执行主动关闭,进入FIN_WAIT_1的状态,从FIN_WAIT_1状态收到FIN包的时候进入CLOSING状态,然后回复ACK,进入TIME_WAIT状态。

参考:《TCP/IP详解》卷一



猜你喜欢

转载自blog.csdn.net/weixin_39138071/article/details/79798808