2015-07-12 7 views
8

Sono solo un principiante in tutto questo settore che comprende websocket, Ratchet e ZeroMQ.Come associare il socket ZeroMQ alla libreria di socket Web di Ratchet per creare un'applicazione in tempo reale per l'applicazione php?

Per la mia conoscenza di base:

websocket è qualcosa che aiuta a creare una connessione aperta tra server e client.

Ratchet è una libreria basata su PHP che utilizza le funzioni di core Socket di PHP per creare un framework socket PHP che ci consente di semplificare la programmazione di socket PHP.

ZeroMQ è una libreria socket che consente a un'applicazione non-ratchet (altri script PHP) di inviare i dati su Ratchet Socket e web-socket.

Sto seguendo il tutorial trovato in ratchet su "ciao mondo" e "pusher" ma entrambi sembrano incompleti e insegna solo come utilizzare solo la console. Ho anche trovato l'esempio di cricchetto in github ma non è adeguatamente documentato. Stavo cercando un esempio completo (con una pagina html dedicata e javascript)

Di seguito è riportato il codice su cui sto lavorando: Questo è uno dei metodi del controller su cui sto facendo una richiesta Ajax. Questo metodo creerà un nuovo post (diciamo). Voglio aggiornare l'elenco dei post in modo dinamico nel browser di più client trasmettendo/spingendo con l'aiuto di ZeroMq.

Metodo in un controllore:

public function create_new_post(){ 
    // ------ 
    // code to create a new post. 
    // ------- 

    // After creating a post 
    $response = [ 
     'new_post_title' => $title, 
     'post_id'   => $id 
    ]; 

    $context = new ZMQContext(); 
    $socket = $context->getSocket(ZMQ::SOCKET_PUSH, 'my pusher'); 
    $socket->connect("tcp://localhost:8000"); 
    $socket->send(json_encode($response)); 

} 

Pusher File:

use Ratchet\ConnectionInterface; 
use Ratchet\Wamp\WampServerInterface; 

class Pusher implements WampServerInterface{ 

    public function onPostEntry($data){ 
     // Data that were sent by ZeroMQ through create_new_post() method 
     $entry_data = json_decode($data);  

     // AND AFTER THIS, I DONT HAVE CLUE OF WHAT TO DO NEXT !!    

    } 
} 

Shell Script da eseguire server:

require dirname(__DIR__) . '/vendor/autoload.php'; 

$loop = React\EventLoop\Factory::create(); 
$pusher = new MyApp\Pusher; 

// Listen for the web server to make a ZeroMQ push after an ajax request 
$context = new React\ZMQ\Context($loop); 
$pull = $context->getSocket(ZMQ::SOCKET_PULL); 
$pull->bind('tcp://127.0.0.1:8000'); 
$pull->on('message', array($pusher, 'onBidEntry')); 

// Set up our WebSocket server for clients wanting real-time updates 
$webSock = new React\Socket\Server($loop); 
$webSock->listen(8080, '0.0.0.0'); 
$webServer = new Ratchet\Server\IoServer(
    new Ratchet\Http\HttpServer(
     new Ratchet\WebSocket\WsServer(
      new Ratchet\Wamp\WampServer(
       $pusher 
      ) 
     ) 
    ), 
    $webSock 
); 

$loop->run(); 

script di Shell dice solo che servirà in porto 8080, tuttavia come potrei menzionare i miei percorsi. Diciamo che voglio la connessione aperta solo nella pagina 'mysite/allposts'. Inoltre, quale sarebbe lo script che devo scrivere in client (un file javascript) e come ricevere questi nuovi dati dal lato client aggiornando un particolare oggetto DOM.

risposta

3

Ho seguito gli esempi di cui stai parlando. Non mi sembravano incomplete, ma capisco cosa intendi. Ratchet è uno script lato server e consente solo di scrivere un servizio che implementa websocket e che è in grado di ascoltare i messaggi ZMQ. Avvierai lo script Ratchet sulla riga di comando e verrà eseguito come servizio in parallelo ad Apache.

Questo è tutto indipendente dal lato client del websocket. Come loro raccomandano, ho usato Autobahn.js sul lato client. Questa libreria implementa il protocollo WAMP. Semplifica il codice lato client al massimo.

Il problema con il codice è che class Pusher implements WampServerInterface non ha un public function onPostEntry.Questa classe deve implementare l'WampServerInterface, questo significa che deve avere almeno queste funzioni:

  • onSubscribe (ConnectionInterface $ conn, $ argomento)
  • onUnSubscribe (ConnectionInterface $ conn, $ argomento)
  • onOpen (ConnectionInterface $ conn)
  • onClose (ConnectionInterface $ conn)
  • onPublish (ConnectionInterface $ conn, $ argomento, $ evento, array $ escludono, array $ ammissibili
  • onError (ConnectionInterface $ Conn, \ Exception $ e)
  • onZMQMessage ($ jsondata)

Ci possono essere altri per funzioni più avanzate, come call ing procedure remote sui client.

Sul lato mittente (messaggio ZMQ), inserire questo codice:

$zmq = new ZMQWrapper; 
$zqm->publish('posts', $response); 

class ZMQWrapper { 
    function __construct(){ 
     $this->context = new ZMQContext(); 
     $this->socket = $this->context->getSocket(ZMQ::SOCKET_PUSH); 
     $this->socket->setSockOpt(ZMQ::SOCKOPT_LINGER, 500); 
     $this->socket->connect("tcp://127.0.0.1:" . ZMQ_PORT); 
    } 
    function publish($topic, $msg){ 
     $data = ['topic' => "mb.$topic", 'msg' => $msg]; 
     $this->socket->send(json_encode($data), ZMQ::MODE_DONTWAIT); 
    } 
} 

Nel file pusher messo someting come:

public function onSubscribe(ConnectionInterface $conn, $topic) { 
    $log = $this->getLogger(); 
    $topicId = $topic->getId(); 
    $log->info(sprintf('A client subscribed to %s', $topicId)); 
    // you could broadcast that user x joined the discussion 
} 
public function onUnSubscribe(ConnectionInterface $conn, $topic) { 
    $log = $this->getLogger(); 
    $topicId = $topic->getId(); 
    $log->info(sprintf('A client unsubscribed from %s', $topicId)); 
    // you could broadcast that user x leaved the discussion 
} 
public function onOpen(ConnectionInterface $conn) { 
    $log = $this->getLogger(); 
    $log->info(sprintf('Client %d connected', $conn->resourceId)); 
    $this->clients[$conn->resourceId] = array(); // this will allow you to save state information of the client, you can modify in onSubscribe and onUnsubscribe 
    // clients will contain the list of all clients 
} 
public function onClose(ConnectionInterface $conn) { 
    $log = $this->getLogger(); 
    $log->info(sprintf('Client %d disconnected', $conn->resourceId)); 
    // you could broadcast that user x leaved the discussion 
} 
public function onPublish(ConnectionInterface $conn, $topic, $event, array $exclude, array $eligible) { 
    $log = $this->getLogger(); 
    $topicId = $topic->getId(); 
    $log->info(sprintf('Client %d published to %s : %s', $conn->resourceId, $topicId, json_encode($event))); 
    foreach($topic->getIterator() as $peer){ 
     if(!in_array($peer->WAMP->sessionId, $exclude)){ 
      $peer->event($topicId, $event); 
     } 
    } 
} 

L'ultimo pezzo è sul client. Se un utente apre la pagina mysite/allposts, in javascript è incluso autobahn.js. Il websocket sarà reso disponibile sotto la variabile ab. È quindi fai:

Quando si apre la pagina:

var currentSession; 
ab.connect(
    Paths.ws, 
    function(session) { // onconnect 
     currentSession = session 
     onWsConnect(session) 
    }, 
    function(code, reason, detail) {// onhangup 
     onWsDisconnect(code, reason, detail) 
    },{ 
     maxRetries: 60, 
     retryDelay: 2000, 
     skipSubprotocolCheck: true 
    } 
) 
currentSession.subscribe('posts', onPostReceived) 

function onPostReceived(topic, message){ 
    //display the new post 
} 

Quando si chiude la pagina:

currentSession.unsubscribe(topic) 

si nota che ho tenuto tutto molto generale. Questo mi consente di avere diversi tipi di messaggi gestiti dallo stesso sistema. Ciò che differisce sono i messaggi ZMQ e gli argomenti di currentSession.subscribe.

I mia implementazione, tengo anche traccia degli utenti che hanno effettuato l'accesso che hanno aperto la connessione, ma ho rimosso questa parte del codice.

Spero che questo ti possa aiutare.

+0

(non trascinabile) Una cosa importante che ho imparato è che "Ratchet è uno script lato server in grado di ascoltare i messaggi ZMQ". Dal punto di vista del concetto, ho capito questo. Ma non ho capito come funziona in modo tecnico (codifica). Penso che nel metodo del controller (nella domanda precedente) stia creando un messaggio ZMQ che viene trasmesso come messaggio codificato Json a Ratchet. PROPRIO QUI ! Non ho capito dove e come questo messaggio codificato sia stato ricevuto da Ratchet e come Ratchet saprebbe che quel metodo è stato eseguito. Quale parte del codice lo fa? –

+1

Infine ho reso la mia applicazione funzionante con Ratchet anche se questa volta non ho usato ZMQ. La mia applicazione è piccola, quindi ho deciso di non usare ZMQ questa volta. La spiegazione che hai dato su come autobahn.js della sua coerenza con il web-socket è molto utile. Riferirò di nuovo questa risposta in futuro quando dovrò usare ZMQ sulla mia applicazione se la mia applicazione si ingrandisce. –