心跳检测

为什么需要心跳检测?

有些极端情况如客户端掉电、网络关闭、拔网线、路由故障等,这些极端情况都属于连接断开的情况,
然而这些情况如果没有应用层的心跳检测,服务端是无法快速感知的。
服务端定时向客户端发送心跳数据可以解决这个问题。

心跳检测的原理是什么?

判断对方(设备,进程或其它网元)是否正常动行,一般采用定时发送简单的通讯包,
如果在指定时间段内未收到对方响应,则判断对方已经当掉。用于检测TCP的异常断开。

服务端向客户端发送心跳检测,客户端接收到心跳数据后,可以忽略不做任何处理,也可以回应心跳检测,

这就分为两种情况:

  1. 当服务端不要求客户端必须回应心跳检测时,假如客户端遇到掉电等极端情况,
    这时服务端向客户端发送的心跳数据在TCP层面就会发送超时,
    遇到这种超时情况TCP会重试多次(次数及间隔依赖操作系统的配置),多次无果后会断开连接。
    这种极端情况从连接断开到服务端检测到可能要持续至少10分钟

  2. 当服务端要求必须回应检测时,如果服务端在规定的时间内没有收到客户端的任何数据,
    则立刻判定客户端已经断开,服务端就立即断开连接。

心跳检测可以是服务端主动,也可以是客户端主动,一般客户端来发会好点,对服务端压力没那么大

“心跳”分为两种,第一种是客户端发起的心跳,第二种是服务端发起的心跳。

客户端发起的心跳

客户端每隔一段时间发送策略消息Socket服务器,Socket服务器原路返回策略消息
如果客户端在设定时间段内没有收到Socket服务器的返回消息,经重试机制后,判定Socket服务器已Down,关闭连接。

服务端发起的心跳

服务端实时记录每条SocketIO操作时间,每隔一段时间获取所有Socket列表的快照,扫描每条Socket
如果该SocketIO操作时间距当前时间已超出设定值,则判定客户端Down,关闭连接。

基于WorkermanPHP心跳

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<?php

require_once __DIR__.'/Workerman/Autoloader.php';

use Workerman\Worker;
use Workerman\Lib\Timer;

define('HEARTBEAT_TIME', 25); //心跳间隔25秒

$worker = new Worker('text://0.0.0.0:1234');

$worker->onMessage = function ($connection, $msg) {
// 给connection临时设置一个lastMessageTime属性,用来记录上次收到消息的时间
$connection->lastMessageTime = time();
//
};

// 进程启动后设置一个每秒运行一次的定时器
$worker->onWorkerStart = function($worker) {
Timer::add(1, function () use ($worker) {
$time_now = time();
foreach ($worker->connections as $connection) {
// 有可能该connection还没收到过消息,则lastMessageTime设置为当前时间
if (empty($connection->lastMessageTime)) {
$connection->lastMessageTime = $time_now;
continue;
}

// 上次通讯时间间隔大于心跳间隔,则认为客户端已经下线,关闭连接
if ($time_now - $connection->lastMessageTime > HEARTBEAT_TIME) {
$connection->close();
}
}
});
};

Worker::runAll();

Swoole做心跳检测

事实上,Swoole已经内置了心跳检测功能,能自动close掉长时间没有数据来往的连接。
而开启心跳检测功能,只需要设置heartbeat_check_intervalheartbeat_idle_time即可。如下:

1
2
3
4
5
6
$this->serv->set(
array(
'headerbeat_check_interval' => 60,
'headerbeat_idle_time' => 600,
)
);

其中heartbeat_idle_time的默认值是heartbeat_check_interval的两倍。
在设置这两个选项后,swoole会在内部启动一个线程,每隔heartbeat_check_interval秒后遍历一次全部连接,检查最近一次发送数据的时间和当前时间的差,
如果这个差值大于heartbeat_idle_time,则会强制关闭这个连接,并通过回调onClose通知Server进程
结合之前的Timer功能,如果我们想维持连接,就设置一个略小于如果这个差值大于heartbeat_idle_time的定时器,
在定时器内向所有连接发送一个心跳包。如果收到心跳回应,则判断连接正常,如果没有收到,则关闭这个连接或者再次尝试发送。

互联网推送原理: 长连接+心跳机制

参考

Powered by Hexo and Hexo-theme-hiker

Copyright © 2017 - 2023 Keep It Simple And Stupid All Rights Reserved.

访客数 : | 访问量 :