socket学习纪录2: workerman 心跳功能实现

蛰伏已久 蛰伏已久 2018-05-29

心跳及作用

所谓心跳,就是客户端每隔一段时间向服务端发送一段任意的数据,证明客户端还在。

长连接应用必须加心跳,否则连接可能由于长时间未通讯被路由节点强行断开。

心跳作用主要有两个:

1、客户端定时给服务端发送点数据,防止连接由于长时间没有通讯而被某些节点的防火墙关闭导致连接断开的情况。

2、服务端可以通过心跳来判断客户端是否在线,如果客户端在规定时间内没有发来任何数据,就认为客户端下线。这样可以检测到客户端由于极端情况(断电、断网等)下线的事件。

建议值:建议心跳间隔小于60秒


实现方式

  • 服务端:

    在onWorkerStart回调中,设置定时器,每隔1s钟,检查每隔connection的上次数据接收时间lastMessageTime,如果lastMessageTime距离本次检测超过心跳间隔(如10s),则认为该connection断开了链接,触发connection的close回调

    在接收新消息回调onMessage中,设置该connection的lastMessageTime为当前时间

  • 客户端:通过设置定时任务setInterval,每隔一段时间发送一段数据,时间间隔小于服务器间隔,以免因为网络延迟造成心跳未及时接收,比如8s发送一次

代码实现

服务端代码

<?php
require_once __DIR__ . '/Workerman/Autoloader.php';
use Workerman\Worker;
use Workerman\Lib\Timer;

// 心跳间隔25秒

define('HEARTBEAT_TIME', 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();

小程序端代码

wx.onSocketOpen(function (res) {
console.log('WebSocket连接已打开!')
wx.sendSocketMessage({
data: "大家好",
})

setInterval(function(){
wx.sendSocketMessage({
data: "心跳",
})
},8000)
})




分享到

点赞(0)