Javascript 如何将ZeroMQ套接字与Ratchet web套接字库绑定,为php应用程序创建实时应用程序?

Javascript 如何将ZeroMQ套接字与Ratchet web套接字库绑定,为php应用程序创建实时应用程序?,javascript,php,ajax,sockets,ratchet,Javascript,Php,Ajax,Sockets,Ratchet,我只是涉及websocket、Ratchet和ZeroMQ的整个领域的初学者 我的基本理解是: websocket有助于在服务器和客户端之间创建开放连接 Ratchet是一个基于PHP的库,它使用PHP的核心套接字函数创建一个PHP套接字框架,从而简化PHP套接字编程 ZeroMQ是一个套接字库,它帮助非ratchet应用程序(其他PHP脚本)通过ratchet套接字和web套接字发送数据 我正在学习ratchet中关于“hello world”和“pusher”的教程,但这两个教程似乎都不完整

我只是涉及websocket、Ratchet和ZeroMQ的整个领域的初学者

我的基本理解是:

websocket
有助于在服务器和客户端之间创建开放连接

Ratchet
是一个基于PHP的库,它使用PHP的核心套接字函数创建一个PHP套接字框架,从而简化PHP套接字编程

ZeroMQ
是一个套接字库,它帮助非ratchet应用程序(其他PHP脚本)通过ratchet套接字和web套接字发送数据

我正在学习ratchet中关于“hello world”和“pusher”的教程,但这两个教程似乎都不完整,只教如何使用控制台。我也在github中找到了ratchet示例,但它并没有正确的文档记录。我正在寻找一个完整的示例(带有专用的html页面和javascript)

下面是我正在处理的代码:这是我正在为其发出Ajax请求的控制器的方法之一。这个方法将创建一个新的帖子(比如说)。我想在ZeroMq的帮助下,通过广播/推送,在多个客户端的浏览器中动态更新帖子列表

控制器中的一种方法:

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

}
推送器文件:

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脚本:

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

Shell脚本只告诉我们它将在端口8080中工作,但是我如何提及我的路由呢。假设我只想在“mysite/allposts”页面中打开连接。另外,我必须在客户端编写什么脚本(javascript文件),以及如何通过客户端更新特定DOM对象来接收这些新数据

我遵循了您所说的示例。对我来说,它们似乎并不完整,但我理解你的意思。Ratchet是一个服务器端脚本,只允许您编写一个实现WebSocket并能够侦听ZMQ消息的服务。您将在命令行上启动Ratchet脚本,它作为与Apache并行的服务运行

这一切都独立于websocket的客户端。就像他们推荐的那样,我在客户端使用了Autobahn.js。此库实现WAMP协议。它最大限度地简化了客户端代码

代码的问题是,
类推送器实现的WampServerInterface
在PostEntry上没有
公共函数。此类必须实现
WampServerInterface
,这意味着它必须至少具有以下功能:

  • onSubscribe(连接接口$conn,$topic)
  • onUnSubscribe(连接接口$conn,$topic)
  • onOpen(连接接口$conn)
  • onClose(连接接口$conn)
  • onPublish(连接接口$conn、$topic、$event、数组$exclude、数组$qualified
  • OneError(连接接口$conn,\n异常$e)
  • onZMQMessage($jsondata)
还有其他更高级的功能,比如
call
ing客户端上的远程过程

在发送方端(ZMQ消息),输入以下代码:

$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);
    }
}
在推送器文件中放入如下内容:

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);
        }
    }
}
最后一部分在客户端。如果用户打开页面
mysite/allposts
,在javascript中包括
autobahn.js
。websocket将在变量
ab
下可用。然后执行以下操作:

打开页面时:

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
}
关闭页面时:

currentSession.unsubscribe(topic)
您注意到,我将所有内容都非常笼统。这使我能够在同一个系统中处理多种类型的消息。不同之处在于ZMQ消息和
currentSession.subscribe
的参数

在我的实现中,我还跟踪打开连接的登录用户,但我删除了这部分代码


我希望这能对您有所帮助。

(不可归类)我了解到的一件重要事情是“Ratchet是一个能够侦听ZMQ消息的服务器端脚本”。从概念上讲,我理解这一点。但我不太理解它在技术方面(编码)是如何工作的。我认为在控制器的方法中(在上面的问题中)正在创建一条ZMQ消息,该消息将作为Json编码的消息传输给Ratchet。就在那里!我不知道Ratchet在何处以及如何接收该编码消息,以及Ratchet如何知道该方法已运行。代码的哪一部分会这样做?最后,我让我的应用程序使用Ratchet,尽管我没有使用ZMQ我。我的应用程序很小,所以这次选择不使用ZMQ。您对autobahn.js如何与web套接字保持一致的解释非常有用。如果我的应用程序变得更大,我将在将来不得不在应用程序上使用ZMQ时再次参考此答案。