在PHP中实现心跳检测功能,通常是为了检查某个服务或者某个连接是否还活着,或者说是否还在正常工作。这就像我们去医院检查心跳,看看身体是否健康一样。
常用的方法:
-
使用curl或者file_get_contents检测某个URL:
我们可以定期访问一个特定的URL,看看服务器是否响应。如果响应了,那就说明服务器还在“活着”。 -
使用socket连接:
通过socket建立一个到服务器的连接,看看是否能够成功。这也是一种常见的心跳检测方法。 -
使用第三方库或服务:
有些库或服务已经为我们封装好了心跳检测的功能,我们只需要调用就可以了。
底层原理:
心跳检测其实就是定期向服务器发送一个小的请求,然后等待服务器的响应。如果服务器在规定的时间内响应了,那就说明它还在正常工作。如果没有响应或者响应时间过长,那我们就知道服务器可能出问题了。
通俗解释:
想象一下,你有一个好朋友,你们经常一起玩。但是有一天,你突然想知道他在不在家,于是你打了一个电话给他。如果他接了电话并和你说话,那你就知道他在家并且一切正常。但是,如果电话一直没人接或者响了很久才接,那你可能就会想,他是不是不在家或者有什么事情发生了。心跳检测就像是这个打电话的过程,只是我们是用计算机来自动完成的。
一、HTTP 心跳(最常用)
1. 服务端心跳接口
// heartbeat.php
connect('127.0.0.1', 6379);
$clientId = $_GET['client_id'] ?? '';
if (!preg_match('/^[a-zA-Z0-9_-]{1,64}$/', $clientId)) {
http_response_code(400);
echo json_encode(['code' => 1, 'msg' => 'invalid client_id']);
exit;
}
// 关键:用 SETEX 设置 TTL,过期自动失效,无需手动清理
$redis->setex("heartbeat:{$clientId}", 60, time());
$redis->sAdd('clients', $clientId); // 记录所有客户端
echo json_encode([
'code' => 0,
'msg' => 'ok',
'server_time' => time(),
]);
2. 客户端定时上报(浏览器 / 小程序 / App)
const CLIENT_ID = 'device_001';
function sendHeartbeat() {
fetch(`/heartbeat.php?client_id=${CLIENT_ID}`)
.then(r => r.json())
.then(res => {
if (res.code === 0) console.log('心跳正常', res.server_time);
})
.catch(err => console.warn('心跳失败,可能已断网', err));
}
setInterval(sendHeartbeat, 30000); // 30 秒一次
sendHeartbeat(); // 立即执行一次
// 页面切回前台时立即补发一次(移动端很重要)
document.addEventListener('visibilitychange', () => {
if (!document.hidden) sendHeartbeat();
});
3. 扫描离线客户端(可用 crontab 定时执行)
// check_offline.php
connect('127.0.0.1', 6379);
$clients = $redis->sMembers('clients');
foreach ($clients as $id) {
if (!$redis->exists("heartbeat:{$id}")) { // TTL 到期 => 离线
echo "客户端 {$id} 已离线n";
// 触发下线业务:发通知、清理会话、更新数据库...
// $redis->sRem('clients', $id);
}
}
# crontab: 每分钟检查一次 * * * * * /usr/bin/php /path/to/check_offline.php >> /var/log/heartbeat.log 2>&1
二、Workerman WebSocket 心跳
在 WebSocket 长连接中,心跳用于检测死连接和防 NAT/代理超时断链。
count = 4;
// 全局定时扫描,比每个连接各开一个 Timer 更省资源
$worker->onWorkerStart = function (Worker $worker) {
Timer::add(10, function () use ($worker) {
$now = time();
foreach ($worker->connections as $conn) {
if ($now - $conn->lastHeartbeat > 60) {
echo "连接 {$conn->id} 心跳超时,主动断开n";
$conn->close();
}
}
});
};
$worker->onConnect = function (TcpConnection $conn) {
$conn->lastHeartbeat = time();
};
$worker->onMessage = function (TcpConnection $conn, $data) {
$msg = json_decode($data, true);
// 响应客户端 ping
if (($msg['type'] ?? '') === 'ping') {
$conn->lastHeartbeat = time();
$conn->send(json_encode(['type' => 'pong', 'time' => time()]));
return;
}
// === 正常业务逻辑 ===
};
$worker->onClose = function (TcpConnection $conn) {
echo "连接关闭: {$conn->id}n";
};
Worker::runAll();
客户端(JS):
const ws = new WebSocket('ws://127.0.0.1:8282');
ws.onopen = () => {
setInterval(() => {
if (ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({ type: 'ping' }));
}
}, 30000);
};
ws.onmessage = (e) => {
const msg = JSON.parse(e.data);
if (msg.type === 'pong') console.log('心跳正常');
};
三、Swoole WebSocket 心跳(内置支持)
Swoole 提供了开箱即用的心跳配置,无需手写扫描逻辑:
set([
'heartbeat_check_interval' => 30, // 每 30 秒扫描一次
'heartbeat_idle_time' => 60, // 60 秒无数据则断开
]);
$server->on('open', function ($server, $req) {
echo "连接建立: fd={$req->fd}n";
});
$server->on('message', function ($server, $frame) {
if ($frame->data === 'ping') {
$server->push($frame->fd, 'pong'); // 数据帧会刷新 idle 计时
return;
}
// 业务逻辑
});
$server->on('close', function ($server, $fd) {
echo "连接关闭: fd={$fd}n";
});
$server->start();
注意:heartbeat_idle_time 统计的是收到任何数据的时间,所以客户端只要按时发 ping(或任意业务数据)即可续命。
四、主动健康检查(服务存活探测)
用于监控远程 API / 服务的可用性:
true,
CURLOPT_TIMEOUT => $timeout,
CURLOPT_CONNECTTIMEOUT => $timeout,
CURLOPT_HEADER => true,
CURLOPT_NOBODY => false,
]);
$start = microtime(true);
$resp = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$errno = curl_errno($ch);
$error = curl_error($ch);
$cost = round((microtime(true) - $start) * 1000, 2);
curl_close($ch);
return [
'alive' => $errno === 0 && $httpCode === 200,
'http_code'=> $httpCode,
'cost_ms' => $cost,
'error' => $error,
];
}
// 使用
$result = checkService('http://api.example.com/health');
if (!$result['alive']) {
// 告警:邮件 / 钉钉 / 企业微信
error_log("服务异常: " . json_encode($result));
}
到此这篇关于PHP实现心跳检测功能的几种常见方法的文章就介绍到这了,更多相关PHP 心跳检测内容请搜索IT俱乐部以前的文章或继续浏览下面的相关文章希望大家以后多多支持IT俱乐部!
