细说websocket快速重连机制

网易智慧企业web前端开发工程师

引言

在一个完善的即时通讯应用中,websocket是极其关键的一环,它为web应用的客户端和服务端提供了一种全双工的通信机制,但由于它本身以及其底层依赖的TCP连接的不稳定性,开发者不得不为其设计一套完整的保活、验活、重连方案,才能在实际应用中保证应用的即时性和高可用性。就重连而言,其速度严重影响了上层应用的“即时性”和用户体验,试想打开网络一分钟后,微信还不能收发消息的话,是不是要抓狂?

因此,如何在网络变更时快速恢复websocket的可用,就变得尤为重要。

快速了解websocet

Websocket诞生于2008年,在2011年成为国际标准,现在所有的浏览器都已支持。它是一种全新的应用层协议,是专门为web客户端和服务端设计的真正的全双工通信协议,

可以类比HTTP协议来了解websocket协议。它们的不同点:

HTTP的协议标识符是httpwebsocket的是ws

HTTP请求只能由客户端发起,服务器无法主动向客户端推送消息,而websocket可以

HTTP请求有同源限制,不同源之间通信需要跨域,而websocket没有同源限制

相同点:

都是应用层的通信协议

默认端口一样,都是80或443

都可以用于浏览器和服务器间的通信

都基于TCP协议

两者和TCP的关系图:

 

细说websocket快速重连机制

图片来源

重连过程拆解

首先考虑一个问题,何时需要重连?

最容易想到的是websocket连接断了,为了接下来能收发消息,我们需要再发起一次连接。但在很多场景下,即便websocket连接没有断开,实际上也不可用了,比如设备切换网络、链路中间路由崩溃、服务器负载持续过高无法响应等,这些场景下的websocket都没有断开,但对上层来说,都没办法正常的收发数据了。因此在重连前,我们需要一种机制来感知连接是否可用、服务是否可用,而且要能快速感知,以便能够快速从不可用状态中恢复。

一旦感知到了连接不可用,那便可以弃旧图新了,弃用并断开旧连接,然后发起一次新连接。这两个步骤看似简单,但若想达到快,且不是那么容易的。

首先是断开旧连接,对客户端来说,如何快速快速断开?协议规定客户端必须要和服务器协商后才能断开websocket连接,但是当客户端已经联系不上服务器、无法协商时,如何断开并快速恢复?

其次是快速发起新连接。此快非彼快,这里的快并非是立即发起连接,立即发起连接会对服务器带来不可预估的影响。重连时通常会采用一些退避算法,延迟一段时间后再发起重连。但如何在重连间隔和性能消耗间做出权衡?如何在“恰当的时间点”快速发起连接?

带着这些疑问,我们来细看下这三个过程。

 

细说websocket快速重连机制

快速感知何时需要重连

需要重连的场景可以细分为三种,一是连接断开了,二是连接没断但是不可用,三是连接对端的服务不可用了。

第一种场景很简单,连接直接断开了,肯定需要重连了。

而对于后两者,无论是连接不可用,还是服务不可用,对上层应用的影响都是不能再收发即时消息了,所以从这个角度出发,感知何时需要重连的一种简单粗暴的方法就是通过心跳包超时:发送一个心跳包,如果超过特定的时间后还没有收到服务器回包,则认为服务不可用,如下图中左侧的方案;这种方法最直接。那如果想要快速感知呢,就只能多发心跳包,加快心跳频率。但是心跳太快对移动端流量、电量的消耗又会太多,所以使用这种方法没办法做到快速感知,可以作为检测连接和服务可用的兜底机制。

 

细说websocket快速重连机制

如果要检测连接不可用,除了用心跳检测,还可以通过判断网络状态来实现,因为断网、切换wifi、切换网络是导致连接不可用的最直接原因,所以在网络状态由offline变为online时,大多数情况下需要重连下,但也不一定,因为webscoket底层是基于TCP的,TCP连接不能敏锐的感知到应用层的网络变化,所以有时候即便网络断开了一小会,对websocket连接是不会有影响的,网络恢复后,仍然能够正常地进行通信。因此在网络由断开到连接上时,立即判断下连接是否可用,可以通过发一个心跳包判断,如果能够正常收到服务器的心跳回包,则说明连接仍是可用的,如果等待超时后仍没有收到心跳回包,则需要重连,如上图中的右侧。这种方法的优点是速度快,在网络恢复后能够第一时间感知连接是否可用,不可用的话可以快速执行恢复,但它只能覆盖应用层网络变化导致websocket不可用的情况。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpwfdw.html