Latido

Nota: Las aplicaciones de conexión larga deben incluir un latido, de lo contrario, la conexión puede ser forzada a cerrarse por los nodos del enrutador debido a la falta de comunicación durante un período prolongado.

El latido tiene principalmente dos funciones:

  1. El cliente envía datos al servidor en intervalos regulares para evitar que la conexión se cierre debido a que algunos nodos de firewall consideran que no ha habido comunicación durante un tiempo prolongado.

  2. El servidor puede usar el latido para determinar si el cliente está en línea; si el cliente no envía ningún dato dentro del tiempo establecido, se considera que el cliente está fuera de línea. Esto permite detectar eventos en los que el cliente ha dejado de estar en línea debido a situaciones extremas (corte de energía, pérdida de conexión, etc.).

Valor sugerido para el intervalo de latido:

Se recomienda que el cliente envíe un latido en un intervalo menor a 60 segundos, por ejemplo, 55 segundos.

El formato de los datos del latido no tiene requisitos específicos, siempre que el servidor pueda reconocerlo.

Ejemplo de Latido

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

// Intervalo de latido de 55 segundos
define('HEARTBEAT_TIME', 55);

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

$worker->onMessage = function(TcpConnection $connection, $msg) {
    // Establecer temporalmente un atributo lastMessageTime en connection para registrar la última vez que se recibió un mensaje
    $connection->lastMessageTime = time();
    // Otras lógicas de negocio...
};

// Al iniciar el proceso, configurar un temporizador que se ejecute cada 10 segundos
$worker->onWorkerStart = function($worker) {
    Timer::add(10, function() use($worker) {
        $time_now = time();
        foreach($worker->connections as $connection) {
            // Es posible que esta conexión aún no haya recibido ningún mensaje, por lo que se establece lastMessageTime como el tiempo actual
            if (empty($connection->lastMessageTime)) {
                $connection->lastMessageTime = $time_now;
                continue;
            }
            // Si el intervalo desde la última comunicación es mayor que el intervalo de latido, se considera que el cliente ha salido de línea, cerrando la conexión
            if ($time_now - $connection->lastMessageTime > HEARTBEAT_TIME) {
                $connection->close();
            }
        }
    });
};

Worker::runAll();

La configuración anterior indica que si el cliente no envía ningún dato al servidor en más de 55 segundos, el servidor considerará que el cliente ha salido de línea, cerrará la conexión y activará onClose.

Reconexión (Importante)

Independientemente de si el cliente envía latidos o el servidor envía latidos, siempre existe la posibilidad de que la conexión se interrumpa. Por ejemplo, el JavaScript se pausa al minimizar el navegador, al cambiar a otra pestaña, si la computadora entra en modo de suspensión, si el dispositivo móvil cambia de red, si la señal se debilita, si la pantalla del teléfono se apaga, si la aplicación se minimiza, problemas con el enrutador, desconexiones intencionales, etc. Especialmente en entornos de red externos, muchos nodos de enrutamiento limpiarán las conexiones inactivas en menos de un minuto, lo que también explica por qué se recomienda un intervalo de latido menor a un minuto.

Las conexiones son fácilmente interrumpidas en entornos de red externos, por lo que la reconexión es una funcionalidad que las aplicaciones de conexión larga deben tener (la reconexión solo puede ser realizada por el cliente, el servidor no puede implementarla). Por ejemplo, el websocket en el navegador necesita escuchar el evento onclose, y cuando ocurre onclose, se debe establecer una nueva conexión (para evitar cierres abruptos, se recomienda un retraso). Más estrictamente, el servidor también debería enviar datos de latido periódicamente, y el cliente debe vigilar si los datos de latido del servidor están fuera de tiempo; si no ha recibido los datos de latido del servidor en el tiempo establecido, se debe considerar que la conexión se ha interrumpido, cerrar la conexión y establecer una nueva conexión.