前几天听一位客户端同事报Mac上切换网络时会出现假连接现象,需要服务器配合调整心跳策略,以减轻对用户的影响。听到这个现象挺好奇的,原因在于:
据同事描述,有些切换网络的场景应用层是监听不到事件的,导致连接没有走重连逻辑。那具体什么场景监听不到呢?
我主要测试了两个场景:
前一个场景未发现问题,第二个场景复现了问题:
当我从家里的wifi “一朵霸王花" 切到 手机热点”nova 7 SE 5G“时, 对应云会议的IM中出现了一个端发消息另一个端收不到的Case‘:
*说明:上面第一个图是手机端在12:00发送了7、8、9三条消息; 第二个图是同帐号的Mac在12:01却没有收到对应的消息; *
虽然复现了问题,不过还在想:是不是我们云会议产品做的不到位呢?那就也测下微信表现。
结果在微信上也复现了此问题:上面第一个截图是手机微信,在11:34发送了a、b、c、d、e、f、g七个字母,但第二个截图的Mac版微信也没有收到。
不论是云会议,还是微信,均没有弹出网络异常之类的提示,在应用层看来,网络连接是正常的。
由此,基本可以确认,Mac上网络切换时确实会出现应用层监听不到网络变化的问题,客户端同事所言非虚。
但是为什么会导致假连接呢?我不由得想探究下网络连接的原理,以及平时一些常见的关于网络方面的疑惑,诸如:
提到连接,直观的认识可能如下图,两台主机在网络上建立了一条类似于物理世界的连线:
由此可见,所谓的网络连接,只是连接两端的主机双方各自维护的一个IP四元组信息,可以理解为我们在内存中维护的一个结构体变量。
网络变化一般有几种情况:
前两种情况系统都是有事件通知到应用层的,对于长连接应用来说,监听到后一般都会选择断开重连,所以问题不大。
同时这个做法也间接说明了一点:操作系统处理网络变化的方式是抛出事件让各个应用自己处理,系统本身并不会在网络变化时直接干预各应用程序建立的网络连接状态。
这里有一个疑问:为什么从断开到连接(或者从Wifi到4G)都要做断开重连的操作呢,既然网络状态已经正常,直接用原来的连接收发数据包是否可以?
回答这个问题,可能要分情况说明:
所以这个问题中切换Wifi的场景,其实是在切换网络,并会引起IP地址变化,需要应用程序做断开重连操作。但由于监听不到系统的网络变化通知,导致仍然在原连接上接收消息,最终收不到任何消息出现假连接问题。
那这个假连接会持续多久呢?
心跳本质上就是发送数据包,也就是说,需要靠真实的数据传输才能检测连接状态。那如果没有数据传输呢?还能监测到网络已经断开吗?
TCP长连接有一个KeepAlive机制,如果开启则会持续一段时间后,主动发送探测报文来保活,如果连续探测数次都没有响应,则认为此TCP连接已死,主动关闭连接。
不过,TCP默认的KeepAlive触发时间为7200秒,也就是至少两小时以上才可以发现一个死亡连接。
如果没有KeepAlive机制呢?既没有数据传输,又没有keepalive,理论上双方的TCP连接将一直保持存在,是感知不到网络断开的状态的,这个结论可能与大多数程序猿的认知不一样。
先说明下前提,这里讨论的是网络恢复后本地IP地址没有发生变化的场景,也就是回答上面跳过的第二种情况。
与切换网络场景明显的区别在于:连接的IP四元组可能还是有效的。这里的关键要看断开期间是否有数据传输。
Case1. 如果断开期间,服务器与客户端之间有数据传输,此时服务器发送的数据包是收不到客户端Ack的。由于TCP层是可靠协议,会尝试重传,当尝试一定次数仍然失败,则会停止重传,并断开TCP连接。
所以这期间如果客户端恢复了网络,要区分服务器连接是否还存在两种细分场景:
Case2. 如果断开期间,服务器与客户端之间没有数据传输,就和上一个话题中讨论的一样,得看KeepAlive机制是否检测到连接已经断掉,断掉了就只能重连,没断掉时恢复了网络就能继续使用;
对于网络从一个wifi切到另一个wifi这种场景,由于操作系统没有明确的事件通知,那就只能靠心跳来主动检测。
目前是有心跳超时检测机制的,我们能想到的办法:只能尝试缩短心跳时间,尽可能快的感知到连接状态问题来采取操作,不过心跳这种方法注定了只能缓解,无法根除问题。
有的同学可能会有疑问:TCP不是可靠协议吗?为何不能保证连接正常?
以上纯属个人理解,如果路过的大神有发现不对的还请帮忙指正,非常感谢!