问题现象:PC与工控机之间通信,工控机发送SYN,PC一直回复FIN或者RST
问题解释:
1. time_wait产生的原因及作用
下面我们先来简单回顾一下TCP连接关闭动作:
在Linux环境下我们可以如下的方式来统计TCP连接的情况:
# netstat -nat | awk '/^tcp/ {++S[$NF]} END{for(a in S) print S[a], "\t", a}'
1 LAST_ACK
57 LISTEN
113953 ESTABLISHED
5 FIN_WAIT1
16 FIN_WAIT2
2 SYN_SENT
559 TIME_WAIT
上面我们看到,大部分的连接处于ESTABLISHED
状态,目前比较少的处于TIME_WAIT
状态,当前机器看起来还算是正常。
1) time_wait状态如何产生?
通过上面的变迁图,首先调用close()
发起主动关闭的一方,在发送最后一个ACK之后会进入time_wait的状态,也就是说该发送方会保持2MSL
时间之后才会回到初始状态。MSL
指的是数据包在网络中的最大生存时间。在这样一个2MSL
长的等待时间内,定义这个连接的四元组(客户端IP/Port,服务端IP/Port)不能被使用。
2)time_wait状态产生的原因
由TCP状态变迁图可知,假设发起主动关闭的一方(client)最后发送的ACK在网络中丢失,由于TCP协议的重传机制,执行被动关闭的一方(server)将会重发其FIN
,在该FIN到达client之前, client必须维护这条连接状态,也就是说这条TCP连接所对应的资源(client方的local_ip/local_port)不能被立即释放或重新分配,直到另一方重发的FIN达到之后,client重发ACK后,经过2MSL时间周期没有再收到另一方的FIN
之后,该TCP连接才能恢复初始的CLOSED状态。如果主动关闭的一方不维护这样一个TIME_WAIT
状态,那么当被动关闭一方重发的FIN
到达时,主动关闭一方的TCP传输层会用RST包响应对方,这会被对方认为是有错误发生,然而这事实上这只是正常的关闭连接过程,并非异常。
确保被动关闭方收到ACK,连接正常关闭,且不因被动关闭方重传 FIN 影响下一个新连接。
为说明这个问题,我们先假设TCP协议中不存在TIME_WAIT
状态的限制,再假设当前有一条TCP连接(local_ip/local_port, remote_ip/remote_port),因某些原因,我们先关闭,接着很快以相同的四元组建立一条新连接。本文前面介绍过,TCP连接由四元组唯一标识,因此,在我们假设的情况中,TCP协议栈是无法区分前后两条TCP连接的不同的,在它看来,这根本就是同一条连接,中间先释放再建立连接的过程对其来说是感知
不到的。这样就可能发生这样的情况:前一条TCP连接由local peer发送的