2013-07-11 3 views
8

Я работаю в режиме реального времени Symfony приложения с использованием Ratchet библиотеки, в этом приложении мне нужно отправить некоторые данные конкретного пользователя, поэтому логика решения было использовать SessionProvider, который будет прикрепить объект Symfony2 Session для каждого входящего объекта Connection. Как указано в документации, я установил не-собственный обработчик сеанса для хранения моих сеансов, то есть в базе данных через PDO. , и это отлично работает на данный момент, но мне нужно получить объект Connection конкретного пользователя, чтобы отправить ему некоторые данные, поэтому другим способом мне нужно найти объект соединения, который ссылается на этого пользователя, и я не могу найти способ сделай это ? ее мой код сервера:Как получить объект соединения конкретного пользователя?

$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(); 
+0

Но как отправить сообщение определенному пользователю? Как реализовать это в примере из 2 клиентов, подключенных к одному серверу WebSocket, каждый со своим собственным объектом подключения: $ ConnSender, $ ConnReceiver? Пожалуйста, уточните мне. Я не нахожу никакого ответа на это в теге ratchet SO.thanks –

+0

каждый раз, когда пользователь подключается к серверу веб-сервера, я получаю его идентификатор, и я храню его объект соединения в массив, проиндексированный его идентификатором , поэтому, когда я хочу отправить некоторые данные этому клиенту, я просто получаю его объект соединения, используя свой идентификатор, и я использую его для отправки моих данных. –

+0

Я понимаю, что вы имеете в виду, но, пожалуйста, позвольте мне добавить еще один вопрос, потому что это не ясно для меня. Когда у меня будет массив, содержащий два объекта соединения с двумя разными идентификаторами (Id1 отправителя и Id2 получателя), как сервер WebSocket получит Id2 для отправки ему сообщения? '$ client = $ this-> clients [$ Id2]; $ client-> send (« Message »);' –

ответ

8

Я был точно такой же вопрос я (минус Symfony), и вот что я сделал.

Основываясь на hello world tutorial, я заменил SplObjectStorage на массив. Прежде чем представить свои изменения, я хотел бы прокомментировать, что, если вы следовали этому учебнику и понимали его, единственное, что помешало вам самому прийти к этому решению, вероятно, не знает, что такое SplObjectStorage.

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(); 
    } 
} 

Конечно, чтобы сделать это действительно полезно вы можете также добавить в связи с БД, и магазин/получить эти resourceIds.

+0

Думает, что у меня уже есть это решение, но мне просто интересно, почему в официальном документе Rachet они говорят, что нам нужно привязать каждый объект подключения к сеансу symfony с помощью обработчика сеанса ... Если мы сможем это сделать, просто используя sqlObjectStorage и Идентификаторы клиентов? –

+0

Я думаю, что они означают это: «дайте доступ к данным сеанса только для чтения с вашего сайта». –

+1

Что делать, если я сам меняю ресурсы? Вот что я делаю: всякий раз, когда я устанавливаю соединение, я немедленно отправляю сообщение с фактическим идентификатором этого пользователя (а не его resourceId, я говорю об идентификаторе, который я использую, чтобы получить имя пользователя, фамилию и т. Д.), а затем после получения сообщения я изменяю ресурс userId на идентификатор i, отправленный с сообщением, а затем всякий раз, когда я хочу отправить этому пользователю сообщение, я в основном прохожу через хранилище spl и когда я нахожу совпадение с его id, я пришлю ему сообщение. Должен ли я это делать? Безопасно ли заменять resourceIds? – Taurus

0

Это то, что я сделал, имеет некоторые улучшения в той же идее.

добавляет 2 функции, которые вы можете вызвать в другом месте: send_to() и 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(); 
    } 
} 
Смежные вопросы