斜体部分为读者的提问:
按我理解,发送方送rst后直接释放连接,接收方收到rst后也释放连接,不需要回复ack。那么问题在于,如果发送方发送的rst包本身丢掉了,没有到达接收端,而发送方发送之后就关闭连接,会不会造成接收方连接半关闭的状态?
回答这个问题之前,先要了解在哪些情况下TCP的一方会发送RST(Reset)给另外一方。
学习TCP的很多读者,会知道一个TCP连接在数据传输完毕,通常会关闭连接,以释放通信双方的资源,如内存、端口号,以便于其它程序使用,这种正常释放连接的过程,通常使用FIN(Final)状态位来完成。
但FIN状态位不能用来处理异常情况。
异常情况一:
客户端、服务器端TCP连接一切正常,TCP连接由于没有数据传输而出于空闲(Idle)状态。
突然服务器掉电,当服务器重新启动完毕,与客户端的TCP连接状态由于掉电而完全消失。
之后,客户端发给服务器任何消息,都会触发服务器发RST作为回应。
服务器之所以发RST,是因为连接不存在,通过Reset状态位,间接告诉客户端异常情况的存在。
Reset顺利到达客户端
客户端意识到异常发生了,会立马释放该TCP连接所占用的内存资源(状态、数据)、以及端口号。
客户端TCP会通知数据的主人(应用程序),由于TCP连接被对方Reset,数据发送失败。
客户端无需超时等待,立即使用原有端口号,重新发起一个TCP连接,双方状态再一次同步,进入正常通信状态。
Reset没有到达客户端
客户端的状态依然为“established”状态,反正双方的状态已经不同步了,如果客户端有数据、或keepalive要发送,会继续触发服务器发送Reset。
这种情况是由于外界因素影响,使得双方状态不同步,一方为“established”,另一方为“closed”, 重置(Reset)连接状态是最好的方法!
有读者会问,如果客户端一直没有消息发给服务器端,那双方状态的不同步是否会保持到天长地久?
会的!
但是考虑到当前的网络状况,这种可能性是比较小的,因为目前的网络NAT无处不在,为了克服NAT表项没有流量刷新而删除NAT表项,进而影响客户端、服务器端通信,如今的TCP实现会在几十秒发送一次Keepalive,这样即使没有用户流量,Keepalive也会刷新NAT表项,从而避免NAT设备删表操作。
所以双方通信不同步状态,在当今的TCP实现上会很快监测到、并予以纠正。
异常情况二:
通常服务器在某个端口侦听,欢迎全球各地的主机(IP)连接请求,这是最最常见的Internet部署场景。
但,有些服务器对主机IP有限制,只允许某个、某些(段)IP的连接请求,这就是白名单列表,凡是不在白名单列表上的主机,遭遇的就是Reset对待。
也有一些服务器,不允许某个、某些IP的连接请求,这个是黑名单列表,凡是在黑名单列表上的主机,遭遇的也是Reset对待。
异常情况三:
当客户端发起一个TCP连接请求,途径公司防火墙时,防火墙查询自己的安全策略,这是一个不被允许的连接请求,于是防火墙以服务器IP的名义,返还给用户一个Reset状态位,用户以为是服务器发的,其实服务器压根不知道,是防火墙作为中间人发的。
如果对计算机网络有兴趣,欢迎参观我的微信公众号:车小胖谈网络
版权所有,禁止任何形式的转载!
领取专属 10元无门槛券
私享最新 技术干货