Socket系列 | GatewayWorker心跳检测

介绍

现在在做一个功能,就是服务端要知道客户端何时掉线的功能,那么要实现这个功能,首先需要实现客户端向服务端发送心跳请求,以及服务端为客户端进行心跳检测的功能。

为了实现这个功能,使用GatewayWorker框架,实现了一个简单的客户端心跳检测。

什么是GatewayWorker

GatewayWorker基于Workerman开发的一个项目框架,用于快速开发TCP长连接应用,例如app推送服务端、即时IM服务端、游戏服务端、物联网、智能家居等等

GatewayWorker使用经典的Gateway和Worker进程模型。Gateway进程负责维持客户端连接,并转发客户端的数据给BusinessWorker进程处理,BusinessWorker进程负责处理实际的业务逻辑(默认调用Events.php处理业务),并将结果推送给对应的客户端。Gateway服务和BusinessWorker服务可以分开部署在不同的服务器上,实现分布式集群。

GatewayWorker提供非常方便的API,可以全局广播数据、可以向某个群体广播数据、也可以向某个特定客户端推送数据。配合Workerman的定时器,也可以定时推送数据。

什么是WebSocket

WebSocket是一种通信协议,可在单个TCP连接上进行全双工通信。WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就可以建立持久性的连接,并进行双向数据传输。

为什么需要心跳检测?

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

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

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

心跳检测的原理是什么?

客户端定时每X秒(推荐小于60秒)向服务端发送特定数据(任意数据都可),服务端设定为X秒没有收到客户端心跳则认为客户端掉线,并关闭连接触发onClose回调。

这样即通过心跳检测请求维持了连接(避免连接因长时间不活跃而被网关防火墙关闭),也能让服务端比较及时的知道客户端是否异常掉线。

GatewayWorker中如何配置心跳检测?

目前GatewayWorker支持两种心跳检测

  • 客户端定时给服务端发送点数据。服务端设定多少秒内没收到心跳关闭连接(推荐)
  • 服务端定时向客户端发送心跳数据(不推荐)。

客户端定时发送心跳(推荐)

服务端配置

客户端定时(间隔最好小于60秒)向服务端发送心跳。服务端类似以下配置:

$gateway = new Gateway("Websocket://0.0.0.0:8585");

$gateway->pingInterval = 55;

$gateway->pingNotResponseLimit = 1;

$gateway->pingData = '';

以上配置含义是客户端连接pingInterval * pingNotResponseLimit=55秒内没有任何数据传输给服务端则服务端认为对应客户端已经掉线,服务端关闭连接并触发onClose回调。

客户端发送心跳案例

// 1. 连接ws
var ws = new WebSocket('ws://127.0.0.1:9503/ss');
ws.onmessage = function (event{
  let _obj = JSON.parse(event.data);
  if (_obj.msg_type == 'init') {
    send_heartbeat();
  }
  console.log('阿克苏: ' + event.data);
};
function send_heartbeat({
  console.info('心跳检测' + Math.random());
  ws.send('{"msg_type":"ping","msg_content":"老板我在线呢!"}');
  setTimeout(send_heartbeat, 10000);
}
ws.onclose = function ({
  console.log('没有网了,睡觉去了');
};

服务端设置心跳检测(不推荐)

服务端的心跳检测的设置,需要在start_gateway.php文件中进行设置,start_gateway.php文件是 gateway进程启动脚本,包括端口号等设置。

// 心跳间隔
$gateway->pingInterval = 55;


$gateway->pingNotResponseLimit = 0;


//  服务端定时向客户端发送的数据
$gateway->pingData = '{"type":"ping"}';

注意:ThinPHP6.0 中在配置文件 gateway_worker.php

'pingInterval'          => 55,
'pingNotResponseLimit'  => 0,
'pingData'              => '{"type":"ping"}',

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

其中pingNotResponseLimit = 0代表服务端允许客户端不发送心跳,服务端不会因为客户端长时间没发送数据而断开连接。

如果pingNotResponseLimit = 1,则代表客户端必须定时发送数据给服务端,否则pingNotResponseLimit*pingInterval=55秒内没有任何数据发来则关闭对应连接,并触发onClose。

参数说明

  • $gateway->pingInterval = 55; 心跳检测时间间隔 单位:秒。如果设置为0代表不做任何心跳检测。
  • $gateway->pingNotResponseLimit = 1; 客户端连续$pingNotResponseLimit$pingInterval时间内不发送任何数据(包括但不限于心跳数据)则断开链接,并触发onClose。如果设置为0代表客户端不用发送心跳数据,即通过TCP层面检测连接的连通性(极端情况至少10分钟才能检测到连接断开,甚至可能永远检测不到)
  • $gateway->pingData = ''; 当需要服务端定时给客户端发送心跳数据时$gateway->pingData设置为服务端要发送的心跳请求数据,心跳数据是任意的,只要客户端能识别即可。客户端收到心跳数据可以忽略不做任何处理。

由于心跳是周期性检测,实际执行onClose的时间一般会大于pingInterval * pingNotResponseLimit = 55,误差在pingInterval内。

  • eg1:pingInterval = 55 则实际执行onClose的时间范围是:55 < onClose <110
  • eg2:pingInterval = 10 则实际执行onClose的时间范围是:10 < onClose <20

注意

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

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

运行参考


var ws = new WebSocket('ws://127.0.0.1:9503'); 
ws.onmessage = function(event) {
    console.log('阿克苏: ' + event.data);
};
ws.onclose = function() {
    var date = new Date();
    console.log('没有网了,睡觉去了' + date.toLocaleString());
};

let _content = {
    "msg_type""join",
    "room_id""160",
};
ws.send(JSON.stringify(_content));


Socket系列 | GatewayWorker心跳检测

原文始发于微信公众号(开源技术小栈):Socket系列 | GatewayWorker心跳检测

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/248386.html

(0)
李, 若俞的头像李, 若俞

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!