如何使用symfony棘轮向特定的websocket客户端发送消息



有一个symfony应用程序使用带有Ratchet的php websockets(http://socketo.me/docs/sessions)。创建一个websocket应用程序,将接收到的消息广播到所有连接的客户端(web浏览器(,这似乎是非常常见的。但我有一个大问题,那就是只向特定的客户端发送消息(例如,用getUser((加载用户并找到其所属的websocket客户端对象(。

这是我的设置:

// WebsocketServer.php
$server = IoServer::factory(
new HttpServer(
new SessionProvider(
new WsServer(
new WebSocketCommunicator()
),
new MySessionHandler())
),
$this->_websocketPort
);
$server->run();
// Handler for communication with clients
class WebSocketCommunicator implements HttpServerInterface
{
protected $clients;
public function __construct()
{
$this->clients = new SplObjectStorage();
}
public function onOpen(ConnectionInterface $conn, RequestInterface $request = null)
{
echo "URI: " . $conn->httpRequest->getUri()->getHost();
echo "KEY: " . $conn->Session->get('key');

// ==> I need somethink like:
$user = $conn->Session->get('user_from_session')->getId();
// Attach new client
$this->clients->attach($conn);
}
public function onMessage(ConnectionInterface $pClient, $msg)
{
$msgObj = json_decode($msg);
echo "WebSocket-Request msg: " . $msg->msg;
}
}

当使用websocket时,没有常规会话或安全对象可以加载登录的用户实体(->getUser(((。如上面链接中所述,可以使用Symfony2会话对象或包含标头和cookie数据的httpRequest对象。有没有一种方法可以在其中一个实例中检索用户对象甚至用户id?

我能找到的只有这样的例子和解决方法:

打开连接时将用户ID从浏览器发送到websocket服务器

如何使用棘轮网络套接字将数据加载发送到服务器?

https://medium.com/@nihon_rafy/create-a-websocket-server-with-symfony和-ratchet-973a59e2df94

现在有现代的解决方案吗?或者任何一种我可以阅读的教程或参考资料?

我正在为websocket服务器开发Laravel 8.0应用程序、PHP 7.4和cboden/Ratchet包。当后端触发事件时,我需要向用户/用户组发送通知,或者更新UI。

我所做的是:

1( 使用composer安装amphp/websocket客户端包。

2( 创建了一个单独的类,以便实例化一个可以连接到websocket服务器的对象,发送所需的消息并断开连接:

namespace App;
use AmpWebsocketClient;
class wsClient {
public function __construct() {
//
}

// Creates a temporary connection to the WebSocket Server
// The parameter $to is the user name the server should reply to.
public function connect($msg) {
global $x;
$x = $msg;
AmpLoop::run(
function() {
global $x;
$connection = yield Clientconnect('ws://ssa:8090');
yield $connection->send(json_encode($x));
yield $connection->close();
AmpLoop::stop();
}
);
}
}

3(处理程序类中的onMessage((事件如下所示:

/**
* @method onMessage
* @param  ConnectionInterface $conn
* @param  string              $msg
*/   
public function onMessage(ConnectionInterface $from, $msg) {
$data = json_decode($msg);
// The following line is for debugging purposes only
echo "   Incoming message: " . $msg . PHP_EOL;
if (isset($data->username)) {
// Register the name of the just connected user.
if ($data->username != '') {
$this->names[$from->resourceId] = $data->username;
}
}
else {
if (isset($data->to)) {
// The "to" field contains the name of the users the message should be sent to.
if (str_contains($data->to, ',')) {
// It is a comma separated list of names.
$arrayUsers = explode(",", $data->to);
foreach($arrayUsers as $name) {
$key = array_search($name, $this->names);
if ($key !== false) {
$this->clients[$key]->send($data->message);
}
}
}
else {
// Find a single user name in the $names array to get the key.
$key = array_search($data->to, $this->names);
if ($key !== false) {
$this->clients[$key]->send($data->message);
}
else {
echo "   User: " . $data->to . " not found";
}
}
} 
}
echo "  Connected users:n";
foreach($this->names as $key => $data) {
echo "   " . $key . '->' . $data . PHP_EOL;
}
}

正如您所看到的,您希望websocket服务器将消息发送到的用户,在$msg参数中被指定为字符串($data->to(以及消息本身($data>消息(。这两件事是JSON编码的,因此参数$msg可以被视为一个对象。

4(在客户端(布局刀片文件中的javascript(,当客户端连接时,我将用户名发送到websocket服务器(就像你的第一个链接建议的那样(

var currentUser = "{{ Auth::user()->name }}";
socket = new WebSocket("ws://ssa:8090");

socket.onopen = function(e) {
console.log(currentUser + " has connected to websocket server");
socket.send(JSON.stringify({ username: currentUser }));
};

socket.onmessage = function(event) {
console.log('Data received from server: ' + event.data);
};

因此,用户名及其连接号保存在websocket服务器中。

5(处理程序类中的onOpen((方法如下所示:

public function onOpen(ConnectionInterface $conn) {
// Store the new connection to send messages to later
$this->clients[$conn->resourceId] = $conn;
echo " n";
echo "  New connection ({$conn->resourceId}) " . date('Y/m/d h:i:sa') . "n";
}

每次客户端连接到websocket服务器时,其连接号或resourceId都存储在一个数组中。因此,用户名存储在一个数组中($names(,密钥存储在另一个数组($client(中。

6(最后,我可以在我的项目中的任何地方创建PHP websocket客户端的实例:

public function handle(NotificationSent $event) {
$clientSocket = new wsClient();
$clientSocket->connect(array('to'=>'Anatoly,Joachim,Caralampio', 'message'=>$event->notification->data));
}

在本例中,我使用的是通知事件侦听器的handle((方法。

好吧,这是为那些想知道如何从PHP websocket服务器(AKA echo服务器(向一个特定客户端或一组客户端发送消息的人准备的。

最新更新