如何解决如何使用symfony ratchet向特定的websocket客户发送消息?
有一个symfony应用程序,它使用带有棘轮(http://socketo.me/docs/sessions)的php websockets。创建一个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;
}
}
使用websockets时,没有常规会话或安全对象,我可以在其中加载已登录的用户实体(-> getUser())。如上面的链接所述,可以使用包含标题和cookie数据的Symfony2 Session对象或httpRequest对象。有没有办法在其中的实例中检索用户对象甚至用户ID?
我所能找到的就是这样的示例和变通方法:
Send user ID from browser to websocket server while opening connection
How do you send data to the server onload using ratchet websockets?
https://medium.com/@nihon_rafy/create-a-websocket-server-with-symfony-and-ratchet-973a59e2df94
现在有解决这个问题的现代方法吗?还是我可以阅读的任何教程或参考书?
解决方法
我正在为 websocket 服务器开发 Laravel 8.0 应用程序、PHP 7.4 和 cboden/Ratchet 包。 我需要在后端触发事件时向用户/用户组发送通知,或更新 UI。
我所做的是:
1) 使用 composer 安装 amphp/websocket-client 包。
2) 创建了一个单独的类来实例化一个可以连接到 websocket 服务器的对象,发送所需的消息并断开连接:
namespace App;
use Amp\Websocket\Client;
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;
\Amp\Loop::run(
function() {
global $x;
$connection = yield Client\connect('ws://ssa:8090');
yield $connection->send(json_encode($x));
yield $connection->close();
\Amp\Loop::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 服务器时,它的连接号或资源 ID 都存储在一个数组中。这样,用户名存储在一个数组 ($names) 中,而键存储在另一个数组 ($clients) 中。
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 服务器(也称为回显服务器)向一个特定客户端或一组客户端发送消息的任何人。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。