网络通信超时之后该不该重启客户端

我写这篇文章来论证“超时之后要不要重启客户端”、“如何重启客户端”。简而言之,重启客户端还是为了让系统能够达到自愈,是比较高的可靠性要求。如果你的软件没有这么高的可靠性要求,像是人机交互程序等对可靠性要求较低的场景,可以选择不考虑这个功能。毕竟实现这个功能的时间至少够300倍你重新点击按钮/重启的时间了。

如果是一些串口协议,通过传输的间隙来判断报文的间隔,比如modbus协议,3.5个时间内不发送,就计算做一个协议报文的开始,那么故障时的报文毫无疑问会处理失败(因为存在CRC校验,奇偶校验等)。等待故障结束,又3.5个时间后,就会恢复正常。

如果能确保网络通信报文不会遭到篡改、也没有宇宙射线/太阳黑子修改你的比特位的场景下,笔者认为没有特别大的必要对客户端进行重启操作,因为不见得重启后就比之前更好,这种超时通常是由服务端处理时间长导致的。没做到建链限制的情况下,贸然重启,还可能会引起建链的波峰。

但是,在实际复杂的网络环境下,如网络报文遭到篡改部分字节丢失等的情况下,一切就大不一样了,不重启客户端就无法自愈。这其中的关键在于,切分报文是否正确。

比如基于TCP的网络协议,这也是本文重点讨论的场景,假设应用协议采用最常见的LengthBasedFrame分包方式,这种协议,通常根据前0~4个字节来判断协议的总长度,比如前面的字节是00000014,那这个报文长度就是1*16 + 4 = 20长度。这种时候,一旦发生了报文篡改/丢包,会导致通信端计算报文长度出错,一直在傻等,无法自愈。

比如上面的例子一旦发生篡改,将4篡改5,那么就会导致客户端/服务器一直在等待不存在的第21个字节,这种情况下,如果不做超时重建,那么这条链路就会一直处于等待状态,无法自愈。

综上所述,实际复杂的网络环境下出现通信超时,这条链路可能会无法自愈。这种情况下,笔者推荐对针对tcp链路做超时重建,业内的一些例子像是:bookkeeper client没有做,kafka client做了。至于重建的触发条件,比如一次超时就重建、多次超时之后才重建、仅当心跳报文超时才重建,这些就交给读者自己把握了。如果区别不大,笔者倾向于一次超时就重建,逻辑简单清晰。