Cómo enviar datos a un cliente específico en Workerman
Utilizando un worker para hacer un servidor, sin usar GatewayWorker, ¿cómo se implementa el envío de mensajes a un usuario específico?
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
require_once __DIR__ . '/vendor/autoload.php';
// Inicializar un contenedor worker, escuchando en el puerto 1234
$worker = new Worker('websocket://workerman.net:1234');
// ==== el número de procesos debe ser 1 ====
$worker->count = 1;
// Agregar una nueva propiedad para guardar el mapeo de uid a conexión (uid es el id de usuario o un identificador único del cliente)
$worker->uidConnections = array();
// Función de callback que se ejecuta cuando un cliente envía un mensaje
$worker->onMessage = function(TcpConnection $connection, $data)
{
global $worker;
// Comprobar si el cliente actual ya está autenticado, es decir, si se ha establecido un uid
if(!isset($connection->uid))
{
// Si no ha pasado la verificación, se toma el primer paquete como uid (esto es solo para facilitar la demostración, no se ha hecho una verdadera verificación)
$connection->uid = $data;
/* Guardar el mapeo de uid a conexión, así se pueden encontrar las conexiones fácilmente usando el uid,
* permitiendo enviar datos a un uid específico
*/
$worker->uidConnections[$connection->uid] = $connection;
return $connection->send('inicio de sesión exitoso, tu uid es ' . $connection->uid);
}
// Otra lógica, enviar a un uid específico o transmisión global
// Suponiendo que el formato del mensaje es uid:message, se envía el message al uid
// Si uid es all, es una transmisión global
list($recv_uid, $message) = explode(':', $data);
// Transmisión global
if($recv_uid == 'all')
{
broadcast($message);
}
// Enviar a un uid específico
else
{
sendMessageByUid($recv_uid, $message);
}
};
// Cuando un cliente se desconecta
$worker->onClose = function(TcpConnection $connection)
{
global $worker;
if(isset($connection->uid))
{
// Al desconectarse, eliminar el mapeo
unset($worker->uidConnections[$connection->uid]);
}
};
// Enviar datos a todos los usuarios autenticados
function broadcast($message)
{
global $worker;
foreach($worker->uidConnections as $connection)
{
$connection->send($message);
}
}
// Enviar datos a un uid específico
function sendMessageByUid($uid, $message)
{
global $worker;
if(isset($worker->uidConnections[$uid]))
{
$connection = $worker->uidConnections[$uid];
$connection->send($message);
}
}
// Ejecutar todos los workers (en realidad solo se ha definido uno)
Worker::runAll();
Nota:
El ejemplo anterior puede enviar mensajes específicos a un uid, aunque está en un solo proceso, soporta unas 100,000 conexiones en línea sin problemas.
Este ejemplo solo puede ejecutarse en un solo proceso, es decir, $worker->count debe ser 1. Para soportar múltiples procesos o clústeres de servidores, se necesita el componente Channel para completar la comunicación entre procesos, lo cual es muy fácil de desarrollar. Puedes consultar el ejemplo de transmisión en clúster con el componente Channel.
Si deseas enviar mensajes a los clientes desde otros sistemas, puedes consultar la sección sobre enviar en otros proyectos.