Как отправить данные на конкретного клиента в Workerman
Если вы используете worker в качестве сервера, а не GatewayWorker, то как реализовать отправку сообщений определенному пользователю?
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
require_once __DIR__ . '/vendor/autoload.php';
// Инициализация контейнера worker, слушающего порт 1234
$worker = new Worker('websocket://workerman.net:1234');
// ==== ЗДЕСЬ КОЛИЧЕСТВО ПРОЦЕССОВ ДОЛЖНО БЫТЬ УСТАНОВЛЕНО В 1 ====
$worker->count = 1;
// Добавление нового свойства для сохранения соответствия uid и соединения (uid - идентификатор пользователя или уникальный идентификатор клиента)
$worker->uidConnections = array();
// Функция обратного вызова, когда клиент отправляет сообщение
$worker->onMessage = function(TcpConnection $connection, $data)
{
global $worker;
// Проверяем, прошел ли текущий клиент проверку, т.е. установлен ли uid
if(!isset($connection->uid))
{
// Если не прошел, то первый пакет считается uid (для удобства демонстрации, здесь не выполняется реальная проверка)
$connection->uid = $data;
/* Сохраняем соответствие uid и соединения, таким образом, можно легко найти соединение по uid и отправлять данные для конкретного uid */
$worker->uidConnections[$connection->uid] = $connection;
return $connection->send('login success, your uid is ' . $connection->uid);
}
// Другая логика, отправка данных конкретному uid или глобальное распространение
// Предположим, что формат сообщения uid:message означает отправку сообщения для uid
// uid - all означает глобальную рассылку
list($recv_uid, $message) = explode(':', $data);
// Глобальная рассылка
if($recv_uid == 'all')
{
broadcast($message);
}
// Отправка конкретному uid
else
{
sendMessageByUid($recv_uid, $message);
}
};
// При отключении клиента
$worker->onClose = function(TcpConnection $connection)
{
global $worker;
if(isset($connection->uid))
{
// Удаление соответствия при отключении соединения
unset($worker->uidConnections[$connection->uid]);
}
};
// Отправка данных всем авторизованным пользователям
function broadcast($message)
{
global $worker;
foreach($worker->uidConnections as $connection)
{
$connection->send($message);
}
}
// Отправка данных по uid
function sendMessageByUid($uid, $message)
{
global $worker;
if(isset($worker->uidConnections[$uid]))
{
$connection = $worker->uidConnections[$uid];
$connection->send($message);
}
}
// Запуск всех worker (фактически определен только один)
Worker::runAll();
Примечание:
В приведенном выше примере можно осуществлять отправку по uid, хотя процесс является однопроцессным, но он поддерживает без проблем 10 тыс. онлайн.
Обратите внимание, что в этом примере может быть только один процесс, то есть $worker->count должно быть равно 1. Чтобы поддерживать несколько процессов или кластер серверов, необходимо использовать компонент Channel для межпроцессного взаимодействия. Разработка также очень проста, и вы можете обратиться к разделу Пример кластеризации компонента Channel.
Если вы хотите отправлять сообщения клиентам из других систем, обратитесь к разделу Отправка сообщений в другом проекте