Cách gửi dữ liệu đến một khách hàng cụ thể trong Workerman
Sử dụng worker để xây dựng máy chủ, không sử dụng GatewayWorker, làm thế nào để gửi thông điệp đến 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');
// ==== số tiến trình ở đây phải phải phải được đặt thành 1 ====
$worker->count = 1;
// Thêm một thuộc tính mới để lưu ánh xạ uid tới connection (uid là id người dùng hoặc định danh duy nhất của khách hàng)
$worker->uidConnections = array();
// Hàm callback được thực thi khi có khách hàng gửi tin nhắn
$worker->onMessage = function(TcpConnection $connection, $data)
{
global $worker;
// Xác định xem khách hàng hiện tại đã xác thực hay chưa, tức là đã thiết lập uid hay chưa
if(!isset($connection->uid))
{
// Nếu chưa xác thực thì coi gói đầu tiên là uid (ở đây để tiện cho việc trình diễn, không thực hiện xác thực thực sự)
$connection->uid = $data;
/* Lưu uid vào ánh xạ connection, như vậy có thể dễ dàng tìm connection qua uid,
* thực hiện gửi dữ liệu đến 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 đến một uid cụ thể hoặc phát sóng toàn cầu
// Giả sử định dạng tin nhắn là uid:message thì gửi message đến uid
// uid là all thì sẽ phát sóng toàn cầu
list($recv_uid, $message) = explode(':', $data);
// Phát sóng toàn cầu
if($recv_uid == 'all')
{
broadcast($message);
}
// Gửi đến uid cụ thể
else
{
sendMessageByUid($recv_uid, $message);
}
};
// Khi có khách hàng ngắt kết nối
$worker->onClose = function(TcpConnection $connection)
{
global $worker;
if(isset($connection->uid))
{
// Khi kết nối ngắt, xoá ánh xạ
unset($worker->uidConnections[$connection->uid]);
}
};
// Gửi dữ liệu đến 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 theo uid
function sendMessageByUid($uid, $message)
{
global $worker;
if(isset($worker->uidConnections[$uid]))
{
$connection = $worker->uidConnections[$uid];
$connection->send($message);
}
}
// Chạy tất cả các worker (trên thực tế hiện tại chỉ định nghĩa một)
Worker::runAll();
Giải thích:
Ví dụ trên có thể gửi đến uid, mặc dù là tiến trình đơn, nhưng hỗ trợ khoảng 10W người dùng trực tuyến là không thành vấn đề.
Lưu ý rằng ví dụ này chỉ có thể chạy trong một tiến trình, tức là $worker->count phải là 1. Để hỗ trợ đa tiến trình hoặc cụm máy chủ, cần phải sử dụng thành phần Channel để hoàn thành giao tiếp giữa các tiến trình, phát triển cũng rất đơn giản, có thể tham khảo ví dụ phát sóng cụm thành phần Channel.
Nếu bạn muốn gửi thông điệp đến khách hàng từ các hệ thống khác, có thể tham khảo gửi thông điệp trong dự án khác.