How to bind ZeroMQ socket with Ratchet web-socket library to make real time application for php application?

后端 未结 1 1593
悲哀的现实
悲哀的现实 2021-02-03 13:39

I am just a beginner in this whole area involving websocket, Ratchet and ZeroMQ.

To my basic understanding:

websocket is something that helps to cr

1条回答
  •  谎友^
    谎友^ (楼主)
    2021-02-03 13:52

    I followed the examples you are talking about. They didn't seem incomplete to me, but I understand what you mean. Ratchet is a server side script and just allows you to write a service that implements websockets and that is able to listen to ZMQ messages. You will launch your Ratchet script on the command line and it runs as a service in parallel to Apache.

    This is all independent from the client side of the websocket. Like they recommend, I used Autobahn.js on the client side. This library implements the WAMP protocol. It simplifies the client side code to the max.

    The problem with your code is, that class Pusher implements WampServerInterface does not have a public function onPostEntry. This class has to implement the WampServerInterface, this means it must have at least these functions :

    • onSubscribe(ConnectionInterface $conn, $topic)
    • onUnSubscribe(ConnectionInterface $conn, $topic)
    • onOpen(ConnectionInterface $conn)
    • onClose(ConnectionInterface $conn)
    • onPublish(ConnectionInterface $conn, $topic, $event, array $exclude, array $eligible
    • onError(ConnectionInterface $conn, \Exception $e)
    • onZMQMessage($jsondata)

    There can be others for more advanced features, like calling remote procedures on clients.

    On the sender side (ZMQ message), put this code:

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

    In the pusher file put someting like:

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

    The last piece is on the client. If a user opens the page mysite/allposts, in javascript you include autobahn.js. The websocket will be made available under the variable ab. You then do:

    When opening the page :

    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
    }
    

    When closing the page:

    currentSession.unsubscribe(topic)
    

    You note that I kept everything very general. This allows me for having several types of messages handled by the same system. What differs are the ZMQ messages and the arguments of currentSession.subscribe.

    I my implementation, I also keep track of the logged in users that opened the connection, but I stripped this part of the code.

    I hope this will help you.

    0 讨论(0)
提交回复
热议问题