• 作者:老汪软件技巧
  • 发表时间:2024-10-17 00:02
  • 浏览量:

为什么需要心跳检测?

正常的情况客户端断开连接会向服务端发送一个fin包,服务端收到fin包后得知客户端连接断开,则立刻触发onClose事件回调。

心跳包格式:WebSocket协议RFC6455中有定义控制帧的格式Ping帧包含一个操作码0x9,Pong帧包含一个操作码0xA。客户端发送Ping帧,服务端收到Ping帧后回一个响应Pong帧。

但是有些极端情况如客户端掉电、网络关闭、拔网线、路由故障等,这些极端情况客户端无法发送fin包给服务端,服务端便无法知道连接已经断开。如果客户端与服务端定时有心跳数据传输,则会比较及时的发现连接断开,触发onClose事件回调。

另外路由节点防火墙会关闭长时间不通讯的socket连接,导致socket长连接断开。所以需要客户端与服务端定时发送心跳数据保持连接不被断开。

心跳原理

客户端定时每X秒(推荐小于60秒)向服务端发送特定数据(任意数据都可),服务端设定为X秒没有收到客户端心跳则认为客户端掉线,并关闭连接触发onClose回调。这样即通过心跳检测请求维持了连接(避免连接因长时间不活跃而被网关防火墙关闭),也能让服务端比较及时的知道客户端是否异常掉线。

心跳包机制

WebSocket心跳包机制WebSocket心跳包是WebSocket协议的保活机制,用于维持长连接。有效的心跳包可以防止长时间不通讯时,WebSocket自动断开连接。

心跳包是指在一定时间间隔内,WebSocket发送的空数据包。常见的WebSocket心跳包机制如下:

客户端

客户端定时向服务器发送心跳数据包,以保持长连接。

服务端

服务器定时向客户端发送心跳数据包,以检测客户端连接是否正常。

以上服务端会定时55秒给客户端发心跳数据{"type":"ping"},而客户端不需要定时向服务端发送心跳数据。

说明

注意

当设置为服务端主动发送心跳时,心跳间隔并不是100%精准。当客户端连接成功后,服务端发来的第一个心跳的时间间隔可能要小于服务器设置的值。

当设置为服务端主动发送心跳时,如果客户端最近有发来数据,那么证明客户端存活,服务端会省略一个心跳,下个心跳大约1.5*$gateway->pingInterval秒后发送。

如果心跳是客户端发送,$gateway->pingNotResponseLimit最好大于0,这样可以及时检测到一些死连接(连接已经断开,但是服务端不知道)

心跳机制原理

WebSocket心跳机制的原理是利用心跳包及时发送和接收数据,保证WebSocket长连接不被断开。

WebSocket心跳机制的原理可以用下面的流程来说明:

客户端建立WebSocket连接。客户端向服务器发送心跳数据包,服务器接收并返回一个表示接收到心跳数据包的响应。当服务器没有及时接收到客户端发送的心跳数据包时,服务器会发送一个关闭连接的请求。服务器定时向客户端发送心跳数据包,客户端接收并返回一个表示接收到心跳数据包的响应。当客户端没有及时接收到服务器发送的心跳数据包时,客户端会重新连接WebSocket心跳机制作用完整代码服务端心跳(不推荐)

修改配置文件config\plugin\webman\gateway-worker\process.php进程配置文件。

控制台检测记录

客户端心跳(推荐)控制台检测记录

断线重连

不管是客户端发送心跳还是服务端发送心跳,连接都有断开的可能。例如浏览器最小化js被暂停、浏览器切换到其它tab页面js被暂停、电脑进入睡眠等等、移动端切换网络、信号变弱、手机黑屏、手机应用切换到后台、路由故障、业务主动断开等。尤其是外网环境复杂,很多路由节点会清理1分钟内不活跃的连接,这也是为什么心跳间隔推荐小于1分钟的原因。

连接在外网环境很容易被断开,所以断线重连是长连接应用必须具备的功能(断线重连只能客户端做,服务端无法实现)。例如浏览器websocket需要监听onclose事件,当发生onclose时建立新的连接(为避免需崩可延建立连接)。更严格一点,服务端也应该定时发起心跳数据,并且客户端需要定时监测服务端的心跳数据是否超时,超过规定时间未收到服务端心跳数据应该认定连接已经断开,需要执行close关闭连接,并重新建立新的连接。