如何在PHP中实现事件监听

Art*_*Ale 7 php concurrency semaphore comet reverse-ajax

这是我的问题:我有一个脚本(让我们称之为comet.php)由AJAX客户端脚本提供,并等待更改发生如下:

while(no_changes){
    usleep(100000);
    //check for changes
}
Run Code Online (Sandbox Code Playgroud)

我不太喜欢这个,它不是很可扩展,它是(imho)"糟糕的做法"我想用信号量(?)或无论如何并发编程技术来改善这种行为.你能告诉我一些如何处理这个问题的技巧吗?(我知道,这不是一个简短的答案,但一个起点就足够了.)

编辑:LibEvent怎么样?

igo*_*orw 13

您可以使用ZeroMQ解决此问题.

ZeroMQ是一个库,它提供增压插座,用于将物品(线程,流程甚至单独的机器)连接在一起.

我假设您正在尝试将数据从服务器推送到客户端.好吧,一个好方法是使用EventSource API(可用的polyfills).

client.js

通过EventSource连接到stream.php.

var stream = new EventSource('stream.php');

stream.addEventListener('debug', function (event) {
    var data = JSON.parse(event.data);
    console.log([event.type, data]);
});

stream.addEventListener('message', function (event) {
    var data = JSON.parse(event.data);
    console.log([event.type, data]);
});
Run Code Online (Sandbox Code Playgroud)

router.php

这是一个长时间运行的进程,它侦听传入的消息并将其发送给任何正在收听的人.

<?php

$context = new ZMQContext();

$pull = $context->getSocket(ZMQ::SOCKET_PULL);
$pull->bind("tcp://*:5555");

$pub = $context->getSocket(ZMQ::SOCKET_PUB);
$pub->bind("tcp://*:5556");

while (true) {
    $msg = $pull->recv();
    echo "publishing received message $msg\n";
    $pub->send($msg);
}
Run Code Online (Sandbox Code Playgroud)

stream.php

每个连接到该站点的用户都会获得自己的stream.php.此脚本长时间运行并等待来自路由器的任何消息.一旦收到新消息,它将以EventSource格式输出此消息.

<?php

$context = new ZMQContext();

$sock = $context->getSocket(ZMQ::SOCKET_SUB);
$sock->setSockOpt(ZMQ::SOCKOPT_SUBSCRIBE, "");
$sock->connect("tcp://127.0.0.1:5556");

set_time_limit(0);
ini_set('memory_limit', '512M');

header("Content-Type: text/event-stream");
header("Cache-Control: no-cache");

while (true) {
    $msg = $sock->recv();
    $event = json_decode($msg, true);
    if (isset($event['type'])) {
        echo "event: {$event['type']}\n";
    }
    $data = json_encode($event['data']);
    echo "data: $data\n\n";
    ob_flush();
    flush();
}
Run Code Online (Sandbox Code Playgroud)

要向所有用户发送消息,只需将其发送到路由器即可.然后,路由器将该消息分发给所有侦听流.这是一个例子:

<?php

$context = new ZMQContext();

$sock = $context->getSocket(ZMQ::SOCKET_PUSH);
$sock->connect("tcp://127.0.0.1:5555");

$msg = json_encode(array('type' => 'debug', 'data' => array('foo', 'bar', 'baz')));
$sock->send($msg);

$msg = json_encode(array('data' => array('foo', 'bar', 'baz')));
$sock->send($msg);
Run Code Online (Sandbox Code Playgroud)

这应该证明您不需要node.js来进行实时编程.PHP可以很好地处理它.

除此之外,socket.io是一个非常好的方法.您可以通过ZeroMQ轻松地将socket.io连接到您的PHP代码.

也可以看看

  • 请注意:我最近做了一些基准测试.在某些时候,这不能很好地扩展.我尝试在短时间内与几百个连接的客户端发送几千条消息.如果您使用的是Apache,由于线程之间的上下文切换量,它会变慢.在某些时候,节点或nginx-push-stream模块将是更好的工具.尽管如此,它可以用PHP而且有效. (3认同)