赞
踩
可以看一下之前的一篇学习笔记,里面提到过类似情况。
如果两端的TCP连接一直没有数据交互,达到了触发TCP保活机制的条件,那么内核里的TCP协议栈就会发送探测报文。
所以,TCP保活机制可以在双方没有数据交互的情况下,通过探测报文,来确定对方的TCP连接是否存活。
前提条件:没有开启 TCP keepalive,且双方都没有数据发送
客户端主机崩溃了,服务端是无法感知到的,再加上服务端没有开启TCP keepalive,没有数据交互的情况下,服务端的TCP连接会一直处于ESTABLISHED连接状态,直到服务端重启进程
所以,在没有使用TCP保活机制且双方不传输数据的情况下,一方的TCP连接处于ESTABLISHED状态,并不代表另一方的连接还一定正常。
TCP连接信息是由内核维护的,所以当服务端的进程崩溃后,内核需要回收该进程所有的TCP连接资源,于是内核会发送一次FIN挥手报文,后续的挥手过程也是在内核完成的,并不需要进程的参与,所以即使服务端进程崩溃了,还是能与客户端完成TCP四次挥手。
在客户端主机宕机后,服务端向客户端发送的报文会得不到任何的响应,在一定时长后,服务端就会触发超时重传机制,重传未得到响应的报文。
服务端重传报文的过程中,客户端主机完成重启后,客户端的内核就会重新接收重传的报文,然后根据报文的信息传递给对应的进程:
所以,只要有一方重启完成后,收到之前的TCP连接的报文,都会回复RST报文,以断开连接。
这种情况,服务端超市重传报文的次数达到一定阈值后,内核就会判定该TCP有问题,然后通过Socket接口告诉应用程序该TCP连接出现了问题,于是服务端的TCP连接就会断开。
TCP的数据报文具体重传几次?
在linux系统中,提供一个叫做tcp_retries2的配置项,默认值是15。这个内核参数是控制TCP连接建立的情况下,超时重传的最大次数。
不过tcp_retries设置了15次,并不代表TCP超时重传了15次才会通知应用程序终止该TCP连接,内核会根据tcp_retries2设置的值,计算出一个timeout(如果tcp_retries2 = 15 ,timeout = 924600ms),如果重传间隔超过了这个timeout,则认为超过了阈值,就会停止重传,然后就会断开TCP连接。
在发生超时重传的过程中,每一轮的超时时间(RTO)是倍数增长的,如果第一轮RTO是200ms,那么第二轮RTO是400ms,第三轮RTO是800ms. . .\
RTO是基于RTT(一个包的往返时间)来计算的,如果RTT较大,那么计算出来的RTO就越大,那么经过几轮的重传后,很快就到达上面的timeout值
最小RTO和最大RTO在Linux内核中已经定义好了:
#define TCP_RTO_MAX ((unsigned)(120*HZ)) #define TCP_RTO_MIN ((unsigned)(HZ/5))
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。