Come inviare dati a un client specifico in Workerman
Utilizzando worker per creare un server, senza usare GatewayWorker, come implementare la trasmissione di messaggi a un utente specifico?
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
require_once __DIR__ . '/vendor/autoload.php';
// Inizializza un contenitore worker, in ascolto sulla porta 1234
$worker = new Worker('websocket://workerman.net:1234');
// ==== Qui il numero di processi deve essere impostato a 1 ====
$worker->count = 1;
// Aggiungi una nuova proprietà per memorizzare il mapping uid a connection (uid è l'ID utente o un identificatore univoco del client)
$worker->uidConnections = array();
// Funzione di callback eseguita quando un client invia un messaggio
$worker->onMessage = function(TcpConnection $connection, $data)
{
global $worker;
// Controlla se il client corrente è già autenticato, ovvero se ha un uid impostato
if(!isset($connection->uid))
{
// Se non è autenticato, considera il primo pacchetto come uid (questo è solo per facilitare la dimostrazione, non viene eseguita una vera autentificazione)
$connection->uid = $data;
/* Salva il mapping uid a connection, in modo da poter facilmente cercare connection tramite uid,
* implementando la trasmissione di dati a un uid specifico
*/
$worker->uidConnections[$connection->uid] = $connection;
return $connection->send('login success, your uid is ' . $connection->uid);
}
// Altra logica, invio a un uid specifico o diffusione globale
// Supponiamo che il formato del messaggio sia uid:message, dove uid invia message
// uid è all per la diffusione globale
list($recv_uid, $message) = explode(':', $data);
// Diffusione globale
if($recv_uid == 'all')
{
broadcast($message);
}
// Invia a un uid specifico
else
{
sendMessageByUid($recv_uid, $message);
}
};
// Quando un client si disconnette
$worker->onClose = function(TcpConnection $connection)
{
global $worker;
if(isset($connection->uid))
{
// Cancella il mapping quando la connessione si interrompe
unset($worker->uidConnections[$connection->uid]);
}
};
// Invia dati a tutti gli utenti autenticati
function broadcast($message)
{
global $worker;
foreach($worker->uidConnections as $connection)
{
$connection->send($message);
}
}
// Invia dati a un uid specifico
function sendMessageByUid($uid, $message)
{
global $worker;
if(isset($worker->uidConnections[$uid]))
{
$connection = $worker->uidConnections[$uid];
$connection->send($message);
}
}
// Esegui tutti i worker (in realtà è stato definito solo uno)
Worker::runAll();
Nota:
L'esempio sopra può effettuare il push specifico per uid, anche se è un singolo processo, supporta tranquillamente fino a 100.000 connessioni attive.
Attenzione, questo esempio può funzionare solo in un singolo processo, quindi $worker->count deve essere 1. Per supportare più processi o un cluster di server, è necessario utilizzare il componente Channel per la comunicazione tra processi, e lo sviluppo è molto semplice; è possibile fare riferimento all'esempio di push del cluster con il componente Channel.
Se si desidera inviare messaggi a un client da altri sistemi, è possibile fare riferimento alla sezione Invio di messaggi in altri progetti