workerman环境下长连接的心跳机制与断线重连
文章首发于 http://wsinbol.github.io/2020/10/14/workerman环境下长连接的心跳机制与断线重连/
引言
心跳与重连
心跳一般是指某端(绝大多数情况下是客户端)每隔一定时间向对端发送自定义指令,以判断双方是否存活,因其按照一定间隔发送,类似于心跳,故被称为心跳指令。
如此看来,心跳就是用来维护客户端与服务端双方都可用的检测工具。当检测到有一方不可用时,就应触发“重连”机制,以保证下次通讯的正常交流。
重连,顾名思义,即重新连接,常见于客户端重新发起,笔者尚未见到有服务端发起重连的例子。。。(书看少了还是真的没有???)
“心跳”与“重连”是相辅相成的。在密集型通讯系统中,双方频繁发布消息,此时的“心跳”就是没有意义的,甚至会成为一种累赘,“重连”也就更无从提起了!但是当客户端越来越多,服务端对于发送消息都难以为继时,就不得不释放一些资源,“踢那些懒惰的家伙下线”!当下线的客户端再次发送消息时,就要提供用户无感知的重连,保证用户体验。充分权衡好“心跳”与“重连”,才能以最小的服务资源发挥最大的能量,这样才能做出一个完美的及时通讯系统。
workerman
workerman是一个高性能的PHP socket 服务器框架,workerman基于PHP多进程以及libevent事件轮询库,PHP开发者只要实现一两个接口,便可以开发出自己的网络应用,例如Rpc服务、聊天室服务器、手机游戏服务器等。
下面,结合workerman环境描述“心跳”与“重连”的几种方案!
方案
啥都不动版
- 服务端配置
注释有关心跳检测的代码,不开启心跳检测的相关配置,workerman默认即是该状态。
// 心跳间隔
// $gateway->pingInterval = 10;
// 可容忍心跳限制次数
// $gateway->pingNotResponseLimit = 2;
// 心跳数据
// $gateway->pingData = '{"type":"ping"}';
// $gateway->pingData = '';
- 客户端配置
客户端不需要定时发送ping,客户端和服务端在相当长的一段时间内维持长链接的状态。(具体时间多长可能是浮动的,至少我看了一个上午它还没有断线。。。下午一觉醒来断了,不知是不是电脑息屏原因所致。Whatever,那不重要,反正不推荐使用这种方式!)
当客户端主动关闭该页面时,服务端能立刻感知该客户端下线,触发onclose事件!
不断发ping版
不断发ping包括两种形式:一种是客户端定时发送ping,一种是服务端主动发送ping。
客户端定时发ping
- 服务端配置
// 心跳间隔
$gateway->pingInterval = 55;
// 可容忍心跳限制次数
$gateway->pingNotResponseLimit = 1;
// 心跳数据
$gateway->pingData = '';
以上配置含义是客户端连接 pingInterval*pingNotResponseLimit=55 秒内没有任何请求则服务端认为对应客户端已经掉线,服务端关闭连接并触发onClose回调。
- 客户端描述
setTimeInterval(function(){
ws.send('ping');
},3000);
服务端主动发ping
- 服务端配置
$gateway = new Gateway("Websocket://0.0.0.0:8585");
$gateway->pingInterval = 55;
$gateway->pingNotResponseLimit = 0;
// 服务端定时向客户端发送的数据
$gateway->pingData = '{"type":"ping"}';
以上服务端会定时55秒给客户端发心跳数据{“type”:”ping”},而客户端不需要定时向服务端发送心跳数据。
其中pingNotResponseLimit = 0,代表服务端允许客户端不发送心跳,服务端不会因为客户端长时间没发送数据而断开连接。
如果pingNotResponseLimit = 1,则代表客户端必须定时发送心跳给服务端,否则pingNotResponseLimit*pingInterval=55秒内没有任何数据发来则关闭对应连接,并触发onClose。
- 客户端描述
什么都不需要做!
断线重连版
该版的前提是服务端已经设置了客户端要在规定时间内发送ping包过来,如果在规定时间内未接收到客户端发送的ping,则服务端会主动将客户端踢下线,触发onclose事件。与此同时,客户端监听到close状态,则会触发断线重连机制。
- setTimeout 定时触发形式(代码节选)
var tt = '';
var lockReconnect = false;//避免重复连接
function reconnect(url) {
if(lockReconnect) {
return;
};
lockReconnect = true;
//没连接上会一直重连,设置延迟避免请求过多
tt && clearTimeout(tt);
tt = setTimeout(function () {
createWebSocket(url);
lockReconnect = false;
}, 4000);
}
- 借助工具断线重连
详细了解见 https://github.com/joewalnes/reconnecting-websocket
使用方法非常简单,引入ReconnectingWebSocket相关文件,将
var ws = new WebSocket('ws://....');
替换为:
var ws = new ReconnectingWebSocket('ws://....');
即可实现断线重连!
支持的功能很多,但了解不多,不予置评!
理想主义版
先来说“心跳”,理想中的心跳是一个浮动的状态。当消息交互频繁时,心跳处于停滞状态,此时发送心跳还占用资源,故没必要。当一段时间内双方没有往来消息时,启动心跳机制,并且两次心跳之间的间隔程逐渐递增状态,同时要有一个阈值来约束,此后维持在阈值水平发包即可。
再看下“重连”,当确实因为不可抗拒的因素导致双方断开后,可根据是否有新的消息或者自身的消息发起建立重连机制,而不是断线后立即发起重连,毕竟重连后相当一段时间内无消息交互再被踢下线也是一种浪费。
一点拙见,欢迎讨论!
参考资料
相关文章
发表评论
评论列表
- 这篇文章还没有收到评论,赶紧来抢沙发吧~