Cách gửi dữ liệu đến một khách hàng cụ thể trong Workerman

Khi sử dụng worker để tạo máy chủ mà không sử dụng GatewayWorker, làm thế nào để triển khai việc gửi tin nhắn cho một người dùng cụ thể?

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

// Khởi tạo một container worker, lắng nghe cổng 1234
$worker = new Worker('websocket://workerman.net:1234');
// ====Phải thiết lập số tiến trình ở đây là 1====
$worker->count = 1;
// Thêm một thuộc tính mới để lưu trữ sự ánh xạ uid đến kết nối (uid là id người dùng hoặc định danh duy nhất của khách hàng)
$worker->uidConnections = array();
// Khi có khách hàng gửi tin nhắn
$worker->onMessage = function(TcpConnection $connection, $data)
{
    global $worker;
    // Kiểm tra xem khách hàng hiện tại đã được xác thực chưa, tức là đã thiết lập uid chưa
    if(!isset($connection->uid))
    {
       // Nếu chưa xác thực, hãy xem gói tin đầu tiên là uid (đây là mục đích minh họa, không có việc xác thực thực sự ở đây)
       $connection->uid = $data;
       /* Lưu uid đến kết nối, điều này giúp dễ dàng tìm kiếm kết nối thông qua uid,
        * triển khai việc gửi dữ liệu cho uid cụ thể
        */
       $worker->uidConnections[$connection->uid] = $connection;
       return $connection->send('Đăng nhập thành công, uid của bạn là ' . $connection->uid);
    }
    // Logic khác, gửi cho một uid cụ thể hoặc gửi toàn cầu
    // Giả sử định dạng tin nhắn là uid:tin nhắn khi gửi tin nhắn cho uid cụ thể
    // Khi uid là tất cả thì sẽ gửi toàn cầu
    list($recv_uid, $message) = explode(':', $data);
    // Gửi toàn cầu
    if($recv_uid == 'all')
    {
        broadcast($message);
    }
    // Gửi cho uid cụ thể
    else
    {
        sendMessageByUid($recv_uid, $message);
    }
};

// Khi có khách hàng kết nối bị ngắt
$worker->onClose = function(TcpConnection $connection)
{
    global $worker;
    if(isset($connection->uid))
    {
        // Xoá ánh xạ khi kết nối bị ngắt
        unset($worker->uidConnections[$connection->uid]);
    }
};

// Gửi dữ liệu cho tất cả người dùng đã xác thực
function broadcast($message)
{
   global $worker;
   foreach($worker->uidConnections as $connection)
   {
        $connection->send($message);
   }
}

// Gửi dữ liệu cho uid cụ thể
function sendMessageByUid($uid, $message)
{
    global $worker;
    if(isset($worker->uidConnections[$uid]))
    {
        $connection = $worker->uidConnections[$uid];
        $connection->send($message);
    }
}

// Chạy tất cả worker (thực ra chỉ định một worker)
Worker::runAll();

Chú ý:

Ví dụ trên cho phép gửi tin nhắn đến uid cụ thể, mặc dù chỉ là một tiến trình, nhưng hỗ trợ cho đến 100.000 người dùng trực tuyến không gặp vấn đề gì.

Lưu ý rằng ví dụ này chỉ hỗ trợ một tiến trình, tức là $worker->count phải là 1. Để hỗ trợ nhiều tiến trình hoặc cụm máy chủ, cần sử dụng thành phần Channel để thực hiện giao tiếp giữa các tiến trình, việc phát triển này cũng rất đơn giản, có thể tham khảo mục Ví dụ phân phối cụm Channel.

Nếu muốn gửi tin nhắn đến khách hàng từ các hệ thống khác, có thể tham khảo mục Gửi tin nhắn trong các dự án khác