2013-07-11 20 views
8

Pracuję w czasie rzeczywistym Symfony aplikacja za pomocą Ratchet bibliotekę, w tej aplikacji trzeba wysłać jakieś dane do konkretnego użytkownika więc rozwiązanie logika było użyć SessionProvider że dołączy obiekt Symfony2 Session do każdego przychodzącego obiektu połączenia. Ponieważ w dokumentacji podano, że mam skonfigurowany nienatywny moduł obsługi sesji do przechowywania moich sesji, tj. W bazie danych za pośrednictwem PDO. i to działa dobrze na chwilę, ale muszę uzyskać obiekt Connection określonego użytkownika, aby wysłać mu trochę danych, więc w inny sposób muszę znaleźć obiekt połączenia, który odwołuje się do tego użytkownika i nie mogę znaleźć sposobu na Zrób to ? ją moja kod serwera:jak uzyskać obiekt połączenia określonego użytkownika?

$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

Ale jak wysłać wiadomość do konkretnego użytkownika? Jak zaimplementować to w przykładzie 2 klientów podłączonych do jednego serwera WebSocket, każdy z własnym obiektem połączenia: $ ConnSender, $ ConnReceiver? Proszę wyjaśnić mi, że nie znajduję żadnej odpowiedzi na ten znacznik z grzechotką SO.thanks –

+0

za każdym razem, gdy użytkownik jest podłączony do serwera Websocket, otrzymuję jego id i przechowuję jego obiekt połączenia w tablicy indeksowanej jego identyfikatorem , więc gdy chcę przesłać dane do tego klienta, otrzymuję jego obiekt połączenia za pomocą jego identyfikatora i używam go do wysyłania moich danych. –

+0

Rozumiem, co masz na myśli, ale proszę pozwolić mi dodać inne pytanie, ponieważ nie jest dla mnie jasne. Kiedy będę mieć tablicę zawierającą dwa obiekty połączenia z dwoma różnymi identyfikatorami (Id1 nadawcy i Id2 odbiornika), w jaki sposób serwer WebSocket otrzyma Id2, aby wysłać mu wiadomość? '$ client = $ this-> clients [$ Id2]; $ client-> send (" Message ");' –

Odpowiedz

8

miałem dokładnie to samo pytanie ja (minus Symfony) i tutaj jest to, co zrobiłem.

Na podstawie hello world tutorial, podstawiłem SplObjectStorage z tablicą. Zanim przedstawię moje modyfikacje, chciałbym powiedzieć, że jeśli skorzystałeś z tego samouczka i zrozumiałeś go, jedyną rzeczą, która uniemożliwiła ci samodzielne znalezienie tego rozwiązania, prawdopodobnie nie jest wiedza o tym, co to jest 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(); 
    } 
} 

Oczywiście, aby był naprawdę przydatny, możesz również dodać połączenie DB i zapisać/pobrać te identyfikatory zasobów.

+0

Myśli, że mam już to rozwiązanie, ale właśnie zastanawiam się, dlaczego w oficjalnym dokumencie Rachet mają mówić, że musimy dołączyć każdy obiekt połączenia do sesji symfony za pomocą obsługi sesji ... Jeśli możemy to zrobić tylko za pomocą sqlObjectStorage i Ids klientów? –

+0

Myślę, że mają na myśli to: "dajesz dostęp tylko do odczytu do danych sesji z twojej strony." –

+1

Co się stanie, jeśli zmienię same identyfikatory zasobów? Oto, co robię: za każdym razem, gdy nawiązuję połączenie, natychmiast wysyłam wiadomość, która ma rzeczywisty identyfikator tego użytkownika (nie jego resourceId, mówię o identyfikatorze używanym do pobierania imienia, nazwiska itp. Użytkownika), a następnie po otrzymaniu wiadomości, zmieniam identyfikator resourceId użytkownika na identyfikator wysyłany wraz z wiadomością, a gdy tylko chcę wysłać temu użytkownikowi komunikat, przeważnie przechodzę przez magazyn spl i gdy znajduję dopasowanie z jego id, wysyłam mu wiadomość. Czy powinienem to robić? Czy można bezpiecznie zastąpić resourceIds? – Taurus

0

To jest to, co zrobiłem, ma pewne ulepszenia w tej samej idei.

dodaje 2 funkcje, które można wywołać w innym miejscu: send_to() i 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(); 
    } 
} 
Powiązane problemy