心拍

注意:長接続アプリケーションでは心拍を追加する必要があります。さもなければ、接続は長時間通信がないためにルーターのノードによって強制的に切断される可能性があります。

心拍の主な作用は2つです:

  1. クライアントが定期的にサーバにデータを送信して、長時間通信がない場合に、いくつかのノードのファイアウォールによって接続が切断されるのを防ぎます。

  2. サーバは心拍を通じてクライアントがオンラインかどうかを判断できます。クライアントが規定の時間内にデータを送信しない場合、クライアントはオフラインと見なされます。これにより、クライアントが極端な状況(停電や断ネットなど)でオフラインになったことを検出できます。

心拍間隔の推奨値:

クライアントが心拍を送信する間隔は60秒未満、例えば55秒を推奨します。

心拍のデータ形式に要求はありません。サーバが認識できれば問題ありません。

心拍の例

<?php
use Workerman\Worker;
use Workerman\Timer;
use Workerman\Connection\TcpConnection;
require_once __DIR__ . '/vendor/autoload.php';

// 心拍間隔55秒
define('HEARTBEAT_TIME', 55);

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

$worker->onMessage = function(TcpConnection $connection, $msg) {
    // connectionに一時的にlastMessageTime属性を設定し、最後に受信したメッセージの時間を記録します
    $connection->lastMessageTime = time();
    // その他のビジネスロジック...
};

// プロセス起動後に10秒ごとに実行されるタイマーを設定します
$worker->onWorkerStart = function($worker) {
    Timer::add(10, 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();

上記の設定では、クライアントが55秒を超えてサーバにデータを送信しない場合、サーバはクライアントがオフラインと見なし、接続を閉じてonCloseをトリガーします。

切断再接続(重要)

クライアントが心拍を送信する場合でも、サーバが心拍を送信する場合でも、接続が切断される可能性があります。例えば、ブラウザが最小化されたときにjsが一時停止されたり、ブラウザが他のタブに切り替えられたときにjsが一時停止されたり、コンピュータがスリープ状態になったり、モバイル端末がネットワークを切り替えたり、信号が弱くなったり、携帯電話の画面が消えたり、モバイルアプリがバックグラウンドに切り替えられたり、ルーターの故障が発生したり、ビジネスが意図的に切断したりなどです。特に外部ネットワーク環境が複雑で、多くのルーターノードが1分間以内にアクティブでない接続を削除するため、心拍間隔が1分未満であることが推奨される理由でもあります。

外部ネットワーク環境では接続が切断されやすいため、切断再接続は長接続アプリケーションに必須の機能です(切断再接続はクライアントのみが行うもので、サーバでは実現できません)。例えば、ブラウザのWebSocketはoncloseイベントを監視し、oncloseが発生したときに新しい接続を確立する必要があります(崩れを避けるために接続を遅延させることができます)。さらに厳密に言うと、サーバも定期的に心拍データを送信すべきであり、クライアントはサーバの心拍データが超過していないかを定期的に監視し、定められた時間を超えてサーバの心拍データを受信していない場合、接続が切断されたものと見なし、closeを実行して接続を閉じ、新しい接続を再確立する必要があります。