Como enviar dados para um cliente específico no Workerman

Usando o worker para fazer o servidor, sem usar o GatewayWorker, como implementar o envio de mensagens para um usuário específico?

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

// Inicializa um container worker, escutando na porta 1234
$worker = new Worker('websocket://workerman.net:1234');
// ==== O número de processos deve ser 1, MUITO IMPORTANTE ====
$worker->count = 1;
// Adiciona uma nova propriedade para salvar o mapeamento de uid para conexão (uid é o ID do usuário ou identificador único do cliente)
$worker->uidConnections = array();
// Função de callback executada quando um cliente envia uma mensagem
$worker->onMessage = function(TcpConnection $connection, $data)
{
    global $worker;
    // Verifica se o cliente atual já está autenticado, ou seja, se o uid está definido
    if(!isset($connection->uid))
    {
       // Se não estiver autenticado, considera o primeiro pacote como uid (aqui para simplificar a demonstração, não fizemos uma autenticação real)
       $connection->uid = $data;
       /* Salva o mapeamento de uid para conexão, assim é fácil encontrar a conexão pelo uid,
        * permitindo enviar dados para um uid específico
        */
       $worker->uidConnections[$connection->uid] = $connection;
       return $connection->send('login success, your uid is ' . $connection->uid);
    }
    // Outras lógicas, enviando para um uid específico ou broadcasting global
    // Supondo que o formato da mensagem é uid:message, onde é enviado um message para o uid
    // Se uid for all, é um broadcasting global
    list($recv_uid, $message) = explode(':', $data);
    // Broadcasting global
    if($recv_uid == 'all')
    {
        broadcast($message);
    }
    // Enviando para um uid específico
    else
    {
        sendMessageByUid($recv_uid, $message);
    }
};

// Quando um cliente desconectar
$worker->onClose = function(TcpConnection $connection)
{
    global $worker;
    if(isset($connection->uid))
    {
        // Ao desconectar, remove o mapeamento
        unset($worker->uidConnections[$connection->uid]);
    }
};

// Envia dados para todos os usuários autenticados
function broadcast($message)
{
   global $worker;
   foreach($worker->uidConnections as $connection)
   {
        $connection->send($message);
   }
}

// Envia dados para um uid específico
function sendMessageByUid($uid, $message)
{
    global $worker;
    if(isset($worker->uidConnections[$uid]))
    {
        $connection = $worker->uidConnections[$uid];
        $connection->send($message);
    }
}

// Roda todos os workers (na verdade, apenas um foi definido)
Worker::runAll();

Nota:

O exemplo acima pode enviar mensagens para o uid, embora seja de um único processo, suporta cerca de 100 mil conexões online sem problemas.

Atenção: Este exemplo só pode ser executado em um único processo, ou seja, $worker->count deve ser 1. Para suportar múltiplos processos ou clusters de servidores, é necessário usar o componente Channel para comunicação entre processos, que é muito simples de desenvolver; você pode se referir ao exemplo de push em cluster com componente Channel.

Se você deseja enviar mensagens para o cliente a partir de outros sistemas, pode se referir à seção push em outros projetos