ハートビート
注意:長期の接続アプリケーションでは、ハートビートを追加する必要があります。そうでないと、通信が長時間ないことにより、ルーティングノードによって強制的に切断される可能性があります。
ハートビートには主に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) {
// この接続がまだメッセージを受信していない可能性があるため、lastMessageTimeを現在の時刻に設定する
if (empty($connection->lastMessageTime)) {
$connection->lastMessageTime = $time_now;
continue;
}
// 前回の通信からの経過時間がハートビート間隔を超える場合、クライアントはすでにオフラインと見なされ、接続は閉じられます。
if ($time_now - $connection->lastMessageTime > HEARTBEAT_TIME) {
$connection->close();
}
}
});
};
Worker::runAll();
上記の設定では、クライアントが55秒間データをサーバーに送信しない場合、サーバーはクライアントがオフラインと見なし、接続を閉じてonCloseをトリガします。
再接続(重要)
クライアントがハートビートを送信するか、サーバーがハートビートを送信するかに関係なく、接続は切断される可能性があります。たとえば、ブラウザが最小化され、JavaScriptが一時停止される、ブラウザが他のタブに切り替わったり、コンピューターがスリープモードに入ったりする場合、モバイル端末がネットワークを切り替えたり、信号が弱くなったり、携帯電話がスリープモードに入ったり、モバイルアプリがバックグラウンドに切り替わったり、ルーターの障害、ビジネスによる切断などです。特に外部ネットワーク環境では、多くのルーティングノードは非アクティブな接続を1分ごとにクリアすることがあります。これが、ハートビート間隔が1分未満であることが推奨される理由でもあります。
外部ネットワーク環境では、接続が簡単に切断されるため、再接続は長時間の接続アプリケーションに必要な機能です(再接続はクライアントのみが行うことができ、サーバーは実装できません)。たとえば、ブラウザのWebsocketはoncloseイベントを監視し、oncloseが発生した場合、新しい接続を確立します(クラッシュを回避するために接続の延長が必要です)。より厳格には、サーバーも定期的にハートビートデータを送信し、クライアントは定期的にサーバーのハートビートデータのタイムアウトを監視し、指定された時間内にサーバーのハートビートデータを受信しない場合、接続が切断されたと見なし、closeを実行し、新しい接続を確立する必要があります。