我只是这个涉及websocket,Ratchet和ZeroMQ的整个领域的初学者。
基本了解:
websocket
有助于在服务器和客户端之间创建开放式连接。
Ratchet
是一个基于PHP的库,它使用PHP的核心Socket函数来创建一个PHP套接字框架,使我们能够轻松进行PHP套接字编程。
ZeroMQ
是一个套接字库,可以帮助非棘轮应用程序(其他PHP脚本)通过Ratchet Socket和web-socket发送数据。
我正在按照棘轮中关于“你好世界”的教程进行操作。和'推动者'但是它们似乎都是不完整的,只讲授如何使用控制台。我也在github中找到了棘轮示例,但没有正确记录。我正在寻找一个完整的例子(使用专用的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));
}
Pusher文件:
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对象来接收这些新数据。
答案 0 :(得分:4)
我按照你正在谈论的例子。他们对我来说似乎并不完整,但我理解你的意思。 Ratchet是一个服务器端脚本,只允许您编写实现websockets的服务,并且能够侦听ZMQ消息。您将在命令行上启动Ratchet脚本,它将作为服务与Apache并行运行。
这完全独立于websocket的客户端。就像他们推荐的那样,我在客户端使用了Autobahn.js。该库实现了WAMP协议。它最大限度地简化了客户端代码。
您的代码存在问题,class Pusher implements WampServerInterface
没有public function onPostEntry
。这个类必须实现WampServerInterface
,这意味着它必须至少具有以下功能:
可能还有其他功能可用于更高级的功能,例如call
客户端上的远程过程。
在发件人方面(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);
}
}
在pusher文件中添加如下内容:
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
的参数。
我的实现,我也跟踪打开连接的登录用户,但我剥离了这部分代码。
我希望这会对你有所帮助。