8

I am working in a real time Symfony app using Ratchet library, in this app I need to send some data to a specific user so the logic solution was to use the SessionProvider that will attach a Symfony2 Session object to each incoming Connection object. As the documentation states I have setup a non-native session handler to store my sessions i.e. in a database via PDO. and that work fine for the moment but I need to get the Connection object of a specific user to send him some data so in other way I need to find the connection object that reference to this user and I can't find a way to do it ? her's my server code :

 $app=new AggregateApplication(); $loop = \React\EventLoop\Factory::create(); $context = new \React\ZMQ\Context($loop); $pull = $context->getSocket(\ZMQ::SOCKET_PULL); $pull->bind('tcp://127.0.0.1:5555'); $pull->on('message', array($app, 'onNotification')); $webSock = new \React\Socket\Server($loop); $webSock->listen(8080, '127.0.0.1'); $handler = $this->getContainer()->get('session.handler'); $server=new \Ratchet\Wamp\WampServer($app); $server = new SessionProvider($server, $handler); $webServer = new \Ratchet\Server\IoServer(new \Ratchet\WebSocket\WsServer($server),$webSock); $loop->run(); 
11
  • But how to send a message to a specific user? How to implement this in the example of 2 clients connected to one WebSocket server, each with it's own connection object :$ConnSender,$ConnReceiver? Please to clarify to me I don't find any answer to this on ratchet tag of SO.thanks Commented Apr 1, 2015 at 13:04
  • 1
    Definetly it's not necessary but what it's recomended is every data you send from client to server need to be done with ajax in a http request then you should use ZMQ to tell webSocketServer to send same data to another client with webSockets because it's a security issue if you handel data in you re websocket server. and even if you use the thread in the link you will pass by you re app code in the thread Commented Apr 1, 2015 at 16:27
  • 1
    Exactly that was my solution to. Commented Apr 1, 2015 at 16:38
  • 1
    thank you very much sir for sharing your experience, especially regarding this part of PHP programming which really lacks simple and clear doc ( in the consideration of newbs). Commented Apr 1, 2015 at 16:44
  • 1
    I have posted a response hope that help. Commented Apr 13, 2015 at 20:32

2 Answers 2

10

I had the exact same question myself (minus Symfony) and here is what I did.

Based on the hello world tutorial, I have substituted SplObjectStorage with an array. Before presenting my modifications, I'd like to comment that if you followed through that tutorial and understood it, the only thing that prevented you from arriving at this solution yourself is probably not knowing what SplObjectStorage is.

class Chat implements MessageComponentInterface { protected $clients; public function __construct() { $this->clients = array(); } public function onOpen(ConnectionInterface $conn) { // Store the new connection to send messages to later $this->clients[$conn->resourceId] = $conn; echo "New connection! ({$conn->resourceId})\n"; } 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'); foreach ($this->clients as $key => $client) { if ($from !== $client) { // The sender is not the receiver, send to each client connected $client->send($msg); } } // Send a message to a known resourceId (in this example the sender) $client = $this->clients[$from->resourceId]; $client->send("Message successfully sent to $numRecv users."); } public function onClose(ConnectionInterface $conn) { // The connection is closed, remove it, as we can no longer send it messages unset($this->clients[$conn->resourceId]); echo "Connection {$conn->resourceId} has disconnected\n"; } public function onError(ConnectionInterface $conn, \Exception $e) { echo "An error has occurred: {$e->getMessage()}\n"; $conn->close(); } } 

Of course to make it really useful you may also want to add in a DB connection, and store/retrieve those resourceIds.

Sign up to request clarification or add additional context in comments.

3 Comments

Thinks I have already this solution but I am just wondering why in the official doc of Rachet they have talk that we need to attach every connection object to a symfony session using session handler... If we can do this just using the sqlObjectStorage and Ids of clients?
I think they mean this: "give you read-only access to the session data from your website."
What if i change the resourceIds themselves ? Here is what i am doing: whenever i establish a connection, i immediately send a message that has the actual id of that user (not his resourceId, i am talking about the id i use to fetch the user's first name, last name, etc), and then upon receiving the message, i change the user's resourceId to the id i sent with the message, and then whenever i want to send that user a message, i basically loop through the spl storage and when i find a match with his id, i send him the message. Should i be doing this? Is it safe to replace resourceIds ?
2

this is what I did, has some improvements on the same idea.

adds 2 functions that you can call elsewhere: send_to() and multicast().

namespace mine; use Ratchet\MessageComponentInterface; use Ratchet\ConnectionInterface; class ws implements MessageComponentInterface { protected $clients; protected $clientids; public function __construct() { $this->clients = new \SplObjectStorage; $this->clientids = array(); } public function multicast($msg) { foreach ($this->clients as $client) $client->send($msg); } public function send_to($to,$msg) { if (array_key_exists($to, $this->clientids)) $this->clientids[$to]->send($msg); } public function onOpen(ConnectionInterface $conn) { $socket_name = "{$conn->resourceId}@{$conn->WebSocket->request->getHeader('X-Forwarded-For')}"; $this->clients->attach($conn,$socket_name); $this->clientids[$socket_name] = $conn; } public function onMessage(ConnectionInterface $from, $msg) { $this->multicast($msg); } public function onClose(ConnectionInterface $conn) { unset($this->clientids[$this->clients[$conn]]); $this->clients->detach($conn); } public function onError(ConnectionInterface $conn, \Exception $e) { $conn->close(); } } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.