Swoole 实践篇之结合 WebSocket 实现心跳检测机制
原文首发链接:Swoole 实践篇之结合 WebSocket 实现心跳检测机制
大家好,我是码农先森。
引言
前段时间在 Swoole 的交流群里,有群友提问:“如何判断用户端是否在线”。我给予的答案是:“通过在客户端实现心跳包” 来实时记录用户端的心跳数据,最终作为用户是否实时在线的依据。
结合我之前的经验,实现一个简单基于 Swoole 的 WebScoket 服务的心跳检测机制。在用户端会每间隔 5s 上报一次心跳数据,在管理端会每间隔 10 s 获取一次心跳数据,用于实时展示用户的在线状态。
技术实现
heartbeat.html
用户端页面主要是上报用户的心跳包,当用户在线时会每间隔 5s 上报一次数据,如果关闭掉该页面则会断开连接不再上报数据。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>WebSocket Heartbeat Example</title>
</head>
<body>
<script>
var socket = new WebSocket('ws://127.0.0.1:9502');
var user_id = getQueryVariable("user_id")
socket.onopen = function() {
console.log('WebSocket 已连接');
setInterval(function() {
if (socket.readyState === WebSocket.OPEN) {
socket.send(JSON.stringify({type: 'SetHeartbeat', user_id: user_id, user_name: "码农先森"+"(" + user_id + ")", "timestamp": Math.floor(Date.now() / 1000)}));
}
}, 5000); // 每隔5秒发送一次心跳数据
};
socket.onerror = function(error) {
console.error('WebSocket 错误:' + error);
};
socket.onclose = function(event) {
console.log('WebSocket 连接已关闭:' + event.code + ', ' + event.reason);
};
function getQueryVariable(variable)
{
var query = window.location.search.substring(1);
var vars = query.split("&");
for (var i=0;i<vars.length;i++) {
var pair = vars[i].split("=");
if(pair[0] == variable){return pair[1];}
}
return(false);
}
</script>
</body>
</html>
admin.html
管理端页面主要是展示用户的在线状态,每间隔 10s 会获取一次心跳数据包,用于实时显示用户的状态状态。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>WebSocket Admin Example</title>
<style>
#json-data{
text-align: center;
border: 1px solid blue;
width: 30%;
}
</style>
</head>
<div id="json-data"></div>
<body>
<script>
var socket = new WebSocket('ws://127.0.0.1:9502');
socket.onopen = function() {
console.log('WebSocket 已连接');
setInterval(function() {
if (socket.readyState === WebSocket.OPEN) {
socket.send(JSON.stringify({type: 'GetHeartbeat', user: "admin"}));
}
}, 10 * 1000); // 定时每10s获取一次心跳数据
};
socket.onmessage = function(e) {
const jsonData = JSON.parse(e.data);
const container = document.getElementById('json-data');
while (container.firstChild) {
container.removeChild(container.firstChild);
}
jsonData.forEach(item => {
const div = document.createElement('div');
div.innerHTML = `<p>用户ID: ${item.user_id}, 用户名称: ${item.user_name}, 状态: ${item.status}</p>`;
container.appendChild(div);
});
};
socket.onerror = function(error) {
console.error('WebSocket 错误:' + error);
};
socket.onclose = function(event) {
console.log('WebSocket 连接已关闭:' + event.code + ', ' + event.reason);
};
</script>
</body>
</html>
websocket_server.php
服务主要是用于接收用户端上报的心跳数据,以及推送用户的心跳数据到管理端页面;心跳数据会存储到 Redis 缓存中,便于更新数据,在推送数据时会判断用户是否超过 30s 没有更新心跳数据,如果是则会判定为离线状态。
<?php
Swoole\Runtime::enableCoroutine($flags = SWOOLE_HOOK_ALL);
// 创建 WebSocket 服务
$server = new Swoole\WebSocket\Server("0.0.0.0", 9502);
// 监听 WebSocket 连接事件
$server->on('open', function (Swoole\WebSocket\Server $server, $request) {
echo "新的客户端连接: {$request->fd}\n";
});
// 监听 WebSocket 消息事件
$server->on('message', function (Swoole\WebSocket\Server $server, $frame) {
$data = json_decode($frame->data, true);
if ($data["type"] == "SetHeartbeat") {
echo "接收到了用户[{$data["user_name"]}]的心跳包\n";
setHeartbeatCache($data);
}
if ($data["type"] == "GetHeartbeat") {
$data = getHeartbeatCache();
$results = [];
foreach($data as $val) {
$val = json_decode($val, true);
$resutl["user_id"] = $val["user_id"];
$resutl["user_name"] = $val["user_name"];
$resutl["status"] = "在线";
// 超过 30 秒没有心跳包, 则离线
if (time() - $val["timestamp"] > 30) {
$resutl["status"] = "离线";
}
$results[] = $resutl;
}
$server->push($frame->fd, json_encode($results));
}
});
// 监听 WebSocket 关闭事件
$server->on('close', function ($ser, $fd) {
echo "客户端 {$fd} 关闭连接\n";
});
// 启 WebSocket 服务
$server->start();
// 设置缓存
function setHeartbeatCache($data) {
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$redis->hSet('heartbeat', $data["user_id"], json_encode($data));
$redis->close();
}
// 获取缓存
function getHeartbeatCache() {
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$data = $redis->hGetAll('heartbeat');
$redis->close();
return $data;
}
总结
这里实现的心跳检测机制是一个基础版的,心跳包的主要作用是用于检测用户端是否存活,有助于我们及时判断用户端是否存在断线的问题。在我之前开发过的项目中,有一个基于物联网在线直播抓娃娃的项目,其中就有需要实时监控设备在线状态的需求,该需求就是使用心跳包来实现的。实际上心跳检测技术,应用更广泛的是实时通信、或设备管理的场景偏多。
Swoole 实践篇之结合 WebSocket 实现心跳检测机制的更多相关文章
- netty心跳检测机制
既然是网络通信那么心跳检测肯定是离不开的,netty心跳检测分为读.写.全局 bootstrap.childHandler(new ChannelInitializer<SocketChanne ...
- 面试官:Netty心跳检测机制是什么,怎么自定义检测间隔时间?
哈喽!大家好,我是小奇,一位热爱分享的程序员 小奇打算以轻松幽默的对话方式来分享一些技术,如果你觉得通过小奇的文章学到了东西,那就给小奇一个赞吧 文章持续更新 一.前言 书接上回,昨天在地里干了一天的 ...
- javascript websocket 心跳检测机制介绍
====测试代码: ==index.html <!DOCTYPE html> <html lang="en"> <head> <meta ...
- Netty 中的心跳检测机制
心跳检测一般存在于建立长连接 或者 需要保活的场景. 心跳的使用场景 长连接的应用场景非常的广泛,比如监控系统,IM系统,即时报价系统,推送服务等等.像这些场景都是比较注重实时性,如果每次发送数据都要 ...
- 分析dubbo心跳检测机制
目的: 维持provider和consumer之间的长连接 实现: dubbo心跳时间heartbeat默认是60s,超过heartbeat时间没有收到消息,就发送心跳消息(provider,cons ...
- Netty — 心跳检测和断线重连
一.前言 由于在通信层的网络连接的不可靠性,比如:网络闪断,网络抖动等,经常会出现连接断开.这样对于使用长连接的应用而言,当突然高流量冲击势必会造成进行网络连接,从而产生网络堵塞,应用响应速度下降,延 ...
- [Swoole系列入门教程 3] 心跳检测
一.Swoole 的4大知识点: 1.TCP/UDP服务器 2.微服务 3.协程 二.同步与异步: 同步买奶茶:小明点单交钱,然后等着拿奶茶: 异步买奶茶:小明点单交钱,店员给小明一个小票,等小明奶茶 ...
- Swoole 心跳检测
Swoole的心跳检测特别简单,只需要配置 heartbeat_check_interval,heartbeat_idle_time就可以了. heartbeat_check_interval:表示服 ...
- WebSocket心跳检测和重连机制
1. 心跳重连原由 心跳和重连的目的用一句话概括就是客户端和服务端保证彼此还活着,避免丢包发生. websocket连接断开有以下两证情况: 前端断开 在使用websocket过程中,可能会出现网络断 ...
- 161114、websocket实现心跳重连
心跳重连缘由 在使用websocket过程中,可能会出现网络断开的情况,比如信号不好,或者网络临时性关闭,这时候websocket的连接已经断开, 而浏览器不会执行websocket 的 onclos ...
随机推荐
- pc=mobile+pad自适应布局:页面结构与打开方式
pc=mobile+pad自适应布局 在这篇文章,咱们重点聊聊自适应布局的页面结构,以及打开页面的几种方式.关于pc=mobile+pad自适应布局的起源.概念.效果,参见文章:自适应布局:pc = ...
- 试用阿里云GPU服务器进行深度学习模型训练
试用阿里云GPU服务器进行深度学习模型训练 最近在用PyTorch时发现在本地训练模型速度一言难尽,然后发现阿里云可以白嫖gpu服务器,只要没有申请过PAI-DSW资源的新老用户都可以申请5000CU ...
- ES6中数组新增了哪些扩展?
一.扩展运算符的应用 ES6通过扩展元素符...,好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列 console.log(...[1, 2, 3])// 1 2 3console.l ...
- eclipse 汉化语言包/中文补丁/简中设置/中英互换
eclipse 汉化语言包/中文补丁/简中设置/中英互换 汉化很简单,使用eclipse内置的软件下载就可以,不需要下载压缩包 官方的说明 Open the install wizard with ' ...
- OSCAR 2022 开源产业大会PolarDB-X、 PolarDB-PG获奖揭晓
简介: 作为全球数据库领导者,阿里云数据库坚定拥抱开源.此次亮相大会,旗下核心开源项目云原生分布式数据库PolarDB-X通过了信通院的 "可信开源项目评估,并以正式成员身份,加入中国信通院 ...
- 一套 SQL 搞定数据仓库?Flink有了新尝试
数据仓库是公司数据发展到一定规模后必然需要提供的一种基础服务,也是"数据智能"建设的基础环节.迅速获取数据反馈不仅有利于改善产品及用户体验,更有利于公司的科学决策,因此获取数据的实 ...
- 深信服智能边缘计算平台与 OpenYurt 落地方案探索与实践
简介:本文将介绍边缘计算落地的机遇与挑战,以及边缘容器开源项目 OpenYurt 在企业生产环境下的实践方案. 作者:赵震,深信服云计算开发工程师,OpenYurt 社区 Member 编者案:在 ...
- 技术解析:一文看懂 Anolis OS 国密生态 | 龙蜥专场
简介: Anolis OS国密是社区在Anolis OS上做的国密技术解决方案. 编者注:本文系两位演讲者整理,他们在2021年阿里云开发者大会的「开源操作系统社区和生态分论坛」上带了分享,演讲主 ...
- [FE] nvm-windows: Microsoft/NPM/Google 推荐 Windows 的 Node.js 版本管理器, posix 的 nvm-sh/nvm
1. 到 github 下载 nvm-setup.zip 并安装. Releases · coreybutler/nvm-windows (github.com) 2. 安装一个版本的 nodejs. ...
- dotnet 6 使用 HttpWebRequest 进行 POST 文件将占用大量内存
我有用户给我报告一个内存不足的问题,经过了调查,找到了依然是使用已经被标记过时的 HttpWebRequest 进行文件推送,推送过程中,由于 System.Net.RequestStream 将会完 ...