问题
I'm trying to build a system where user can subscribe to a category on establishing connection to websocket server and then he will start receiving updates for that category. So far, I have worked with Ratchet and I am able to send message to all the connected clients but the problem is I don't want to send message to all the clients I just want to send the message to the clients who have subscribed the the particular category in which the messages was sent.
PHP Code
Chat.php
<?php
namespace MyApp;
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
class Chat implements MessageComponentInterface
{
protected $clients;
public function __construct()
{
$this->clients = new \SplObjectStorage;
}
public function onOpen(ConnectionInterface $conn)
{
$this->clients->attach($conn);
}
public function onMessage(ConnectionInterface $conn, $msg)
{
foreach ($this->clients as $client)
{
if($conn !== $client)
$client->send($msg);
}
}
public function onClose(ConnectionInterface $conn)
{
$this->clients->detach($conn);
}
public function onError(ConnectionInterface $conn, \Exception $e)
{
echo "An error has occurred: {$e->getMessage()}\n";
$conn->close();
}
}
?>
server.php
<?php
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use MyApp\Chat;
require dirname(__DIR__) . '/Ratchet/vendor/autoload.php';
$server = IoServer::factory(
new HttpServer(
new WsServer(
new Chat()
)
),
8080
);
$server->run();
?>
Client side js code
<script type="text/javascript">
var conn = new WebSocket('ws://localhost:8080');
conn.onopen = function(e) {
console.log("Connection established!");
};
conn.onmessage = function(e) {
console.log(e.data);
};
</script>
回答1:
Basically you want a syntax for sending data to the WebSocket, I reccomend using a JSON object to do this. In your WebSocket class you need a local variable called subscriptions
and a local variable called users
like so.
<?php
namespace MyApp;
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
class Chat implements MessageComponentInterface
{
protected $clients;
private $subscriptions;
private $users;
public function __construct()
{
$this->clients = new \SplObjectStorage;
$this->subscriptions = [];
$this->users = [];
}
public function onOpen(ConnectionInterface $conn)
{
$this->clients->attach($conn);
$this->users[$conn->resourceId] = $conn;
}
public function onMessage(ConnectionInterface $conn, $msg)
{
$data = json_decode($msg);
switch ($data->command) {
case "subscribe":
$this->subscriptions[$conn->resourceId] = $data->channel;
break;
case "message":
if (isset($this->subscriptions[$conn->resourceId])) {
$target = $this->subscriptions[$conn->resourceId];
foreach ($this->subscriptions as $id=>$channel) {
if ($channel == $target && $id != $conn->resourceId) {
$this->users[$id]->send($data->message);
}
}
}
}
}
public function onClose(ConnectionInterface $conn)
{
$this->clients->detach($conn);
unset($this->users[$conn->resourceId]);
unset($this->subscriptions[$conn->resourceId]);
}
public function onError(ConnectionInterface $conn, \Exception $e)
{
echo "An error has occurred: {$e->getMessage()}\n";
$conn->close();
}
}
?>
The javascript to go with that looks a bit like this
<script type="text/javascript">
var conn = new WebSocket('ws://localhost:8080');
conn.onopen = function(e) {
console.log("Connection established!");
};
conn.onmessage = function(e) {
console.log(e.data);
};
function subscribe(channel) {
conn.send(JSON.stringify({command: "subscribe", channel: channel}));
}
function sendMessage(msg) {
conn.send(JSON.stringify({command: "message", message: msg}));
}
</script>
Note: This code is untested I wrote it on the fly from my experience with Ratchet. Good luck :)
回答2:
// SOCKET VARIABLE DECLARATION
var mySocket;
// MESSAGE
const socketMessageListener = function(event) {
var data = JSON.parse(event.data);
};
// OPEN SOCKET
const socketOpenListener = function(event) {
console.log('Connected');
};
// CLOSE OR DISCONNECT SOCKET
const socketCloseListener = function(event) {
if (mySocket) {
console.error('Disconnected.');
}
mySocket = new WebSocket('ws://localhost:8080');
mySocket.addEventListener('open', socketOpenListener);
mySocket.addEventListener('message', socketMessageListener);
mySocket.addEventListener('close', socketCloseListener);
};
// CALL THE LISTENER
socketCloseListener();
function sendMessage(data) {
mySocket.send(JSON.stringify(data));
}
user3049006 i found this code in my research to keep the connection persistent if fail retry the connection again.
回答3:
ok, now I am sharing my experience. You Can Send Token and Insert This toke in onOpen (server.php) in the database. You can Insert Chat Token When User Login. Every Time When User Login New Token is generated and updated. Now Use This Token To Find out user Id in onOpen connection.
var conn = new WebSocket('ws://172.16.23.26:8080?token=<?php echo !empty($_SESSION['user']['token']) ? $_SESSION['user']['token'] : ''; ?>');
conn.onopen = function(e) {
console.log("Connection established!");
};
Now Server.php
public function onOpen(ConnectionInterface $conn) {
$this->clients->attach($conn);
$querystring = $conn->httpRequest->getUri()->getQuery();
parse_str($querystring,$queryarray);
//Get UserID By Chat Token
$objUser = new \users;
$objUser->setLoginToken($queryarray['token']);
$GetUserInfo = $objUser->getUserByToken();
echo "New connection! ({$conn->resourceId})\n";
//save Chat Connection
// Insert the new connection with the user ID to Match to later if user ID in Table Then Update IT with a new connection
}
Now your Connection is established, then send Message To particular users
Client-Side send USerID with received ID and Message
$("#conversation").on('click', '#ButtionID', function () {
var userId = $("#userId").val();
var msg = $("#msg").val();
var receiverId = $("#receiverId").val();
if ( userId != null && msg != null ){
var data = {
userId: userId,
msg: msg,
receiverId: receiverId
};
conn.send(JSON.stringify(data));
$("#msg").val("");
}
});
Server Side
public function onMessage(ConnectionInterface $from, $msg) {
$numRecv = count($this->clients) - 1;
echo sprintf('Connection %d sending message "%s" to %d other connection%s' . "\n",$from->resourceId, $msg, $numRecv, $numRecv == 1 ? '' : 's');
$data = json_decode($msg, true);
echo $data['userId'];
echo $data['msg'];
echo $data['receiverId'];
// Save User ID receiver Id message in table
//Now Get Chat Connection by user id By Table Which is saved onOpen function
$UptGetChatConnection = $objChatroom->getChatConnectionUserID($data['receiverId']);
$ReciId = $UptGetChatConnection[0]['ConnectionID'];
foreach ($this->clients as $client) {
if ($from == $client) {
$data['from'] = "Me";
$data['fromname'] = 5;
} else {
$data['from'] = $user['name'];
$data['fromname'] = 6;
}
echo $client->resourceId;
echo $ReciId."\n";
if($client->resourceId == $ReciId || $from == $client){
$client->send(json_encode($data));
}
}
}
now the message has been sending by connection ID not broadcast only send particular users
来源:https://stackoverflow.com/questions/30953610/how-to-send-messages-to-particular-users-ratchet-php-websocket