【问题标题】:Send output of popen through websockets通过 websockets 发送 popen 的输出
【发布时间】:2015-12-08 20:52:33
【问题描述】:

我正在使用 popen 和 fgets 来异步读取 tcpdump 的输出。

以下代码应在命令行中运行,而不是使用 apache 并在浏览器中查看。

$handle = popen('tcpdump -nnX', 'r');

while (true) {
    $output = fgets($handle);
    print $output . "\n";
}

当我尝试通过 websockets 输出此信息时出现问题。

Websockets 还使用无限循环(用于管理其套接字、滴答声和消息)。

它看起来像:

while (true) {
    @socket_select($read,$write,$except,1);
    foreach ($read as $socket) {
        if ($socket == $this->master) {
            $client = socket_accept($socket);
...

我通过 websocket 使用 $websocket->sendToAll($message); 发送数据。

  • 我不能一个接一个地放置 while 循环,因为它只会运行我首先放置的循环,while (true) { A() }; while (true) { B() }; B() 永远不会被调用

  • 我无法合并 while 循环,因为 websocket 会减慢 popen 的读取速度,反之亦然。 while (true) { A(); B(); } 如果 B 需要很长时间才能完成,A 会运行缓慢。

在这种情况下我该怎么办?我对线程、分叉脚本之间的通信或其他任何东西持开放态度。

【问题讨论】:

  • 不酷,让我的浏览器崩溃,让资源管理器发疯,发出警告>。
  • @IndigoIdentity 添加。我的问题只关注cli,这里不涉及浏览器。 (除了用websockets查看,这里省略了代码)
  • 好吧,这部分是我自己的错,因为我之前通过套接字 ping IP 并输出到浏览器中,所以我已经根深蒂固了这种想法。现在想想,PHP 中的异步套接字连接会很棒。好问题!
  • 我认为这可以通过使用异步 websockets 或异步 shell_exec 来解决。 This 忽略输出。因为this,我可能只使用node.js。

标签: php websocket


【解决方案1】:

这是Producer-Consumer 问题的经典场景。只是你有两个。您可以分解问题以便更容易理解。

  • WebSocket Consumer:此代码将通过 WebSocket 发送数据。您可以将其视为一个单独的线程,其中数据从Q1(只是一个名称)出列并发送。

  • WebSocket 生产者:一旦一些数据到达 WebSocket 门,它就会被排入缓冲区。只是这和上面的队列不一样。让我们将其命名为Q2。这也需要是一个单独的线程,并且一旦将数据排入队列并向适当的使用者发出信号,该线程就会进入睡眠状态。

  • HDD Consumer:此代码将与 WebSocket Consumer 执行相同的操作,唯一的区别是它将数据存储在硬盘上而不是 WebSocket 上。它将有自己的线程并与Q2 一起使用。

  • HDD Producer:我相信您可以猜到它的作用。此代码将从硬盘读取数据并将其放入Q1 队列。像所有生产者一样,它需要向消费者发出信号,通知他们队列中有新项目。

现在回到你的代码,尽管it's completely possible,PHP 并不适合多线程编程。这就是为什么你找不到这么多例子的原因。但如果你坚持,以下是你需要的:

  1. PHP's Thread class

  2. PHP's Mutex class。该类将帮助您防止多个线程同时访问相同的数据。

  3. 调用 Signaling 的东西我在 PHP 中找不到!它被使用 告诉其他线程队列中的某些数据已准备好 消费,或者换句话说,它会唤醒消费者线程 有事做的时候。

最后一句话是,在适当的多线程软件中,您不会使用sleep 函数来降低系统负载/防止系统崩溃。多线程编程就是线程之间的信令和对话。

【讨论】:

  • PHP 中的 POSIX 信号:secure.php.net/manual/en/function.pcntl-signal.php -- 这定义了一个信号处理程序。
  • @Ghedipunk 谢谢,但我认为这些函数是为进程间通信而不是线程间通信而设计的。由于我们谈论的是多线程,整个脚本将在一个进程中,因此使用 PCNTL 函数挂起一个线程应该挂起该进程中的所有线程。我必须承认我自己没有尝试过,这就是我所相信的。
  • 好点,我也没有在多线程环境中尝试过。至少,这是可以玩的。我不得不承认我个人避免使用多线程来支持分叉。
  • 我相信您知道多进程与多线程编程的优缺点。但只是为了记录,在多线程中,共享内存很容易,因为所有线程都在同一个上下文中。但是在多进程编程中,即使有共享内存但也没有多线程那么容易。
【解决方案2】:

wscat 怎么样?以下命令行:

$ printf "hello\\nbye\\n^C" | wscat -c ws://echo.websocket.org

将下面的两行发送到ws://echo.websocket.org

hello
bye

请注意,命令行中的^C 是一个Control-C(不是^C 的两个字母组合)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-10-17
    • 2020-03-29
    • 1970-01-01
    • 1970-01-01
    • 2013-08-26
    • 2018-06-13
    • 1970-01-01
    • 2017-09-28
    相关资源
    最近更新 更多