【问题标题】:Why stream_select on STDIN becomes blocking when cmd.exe loses focus?为什么当 cmd.exe 失去焦点时 STDIN 上的 stream_select 会阻塞?
【发布时间】:2014-02-23 05:25:39
【问题描述】:

目标:在 cmd 中运行 PHP 文件,脚本循环 x 次,并在每次迭代时检查用户是否输入了任何输入(stream_select()STDIN),如果是,则暂停循环,直到用户按 Enter ,然后打印出输入并继续迭代。

问题:只要 cmd.exe 窗口处于焦点状态,脚本就会完美运行 - 当我单击另一个窗口时,脚本会在 stream_select 处暂停并且不会继续,直到我但 cmd 窗口重新成为焦点并发送一些输入(一个简单的回车键就可以了)。没有错误。

问题:为什么失去对 cmd 的关注会影响 stream_select 并阻塞循环? ...并且有解决方法吗? (例如,是否可以检查当前 cmd 窗口是否处于焦点?)

代码示例,在工作目录中使用了 cmd php script.php

<?php
$loopCount = 20;

while ($loopCount) {

    $start = microtime(true);

    echo 'check on "' . $loopCount . '"' . PHP_EOL;

    $stream = fopen('php://stdin', 'r');

    $stream_array = array($stream);
    $write = array();
    $except = array();

    if (stream_select($stream_array, $write, $except, 1, 0)) {
        $input = trim(fgets($stream));
        if ($input) {
            echo 'input was "' . $input . '"' . PHP_EOL;
        }
    }    

    fclose($stream);

    echo $loopCount . ' in ' . (microtime(true) - $start) . PHP_EOL;

    $loopCount--;    

}

我没有成功尝试过的事情:

  • fopenfclose 移出循环
  • ignore_user_abort(1);
  • stream_set_blocking($stream, 0);
  • null0 以及 tv_sectv_usecstream_select() 参数的更高值
  • 检查connection_aborted()connection_status()

环境:Windows 7、XAMPP for windows、PHP 5.4.19 (cli)、Zend Engine v2.4.0

【问题讨论】:

    标签: php stream command-line-interface stdin blocking


    【解决方案1】:

    我认为问题在于,当流接收 EOL 时,stream_select() 也会为 STDIN 返回 1,这就是我认为 cmd 失去焦点时会发生的情况。

    来自http://www.php.net/manual/en/function.stream-select.php

    特别是,流资源在文件结束时也已准备好,在这种情况下 fread() 将返回零长度字符串

    当焦点没有丢失且没有给定输入时,stream_select返回0,传入的$read数组被引用清空。当焦点丢失或给​​出输入时,$read 数组保持不变,您应该从每个索引中读取。

    但这让我们窗口的用户陷入了糟糕的境地,因为我们没有办法使用 stream_get_(contents|line) 或 fread 或 fgets 非阻塞地读取零长度字符串。而且由于我们无法区分失去焦点和提供实际数据,我相信我们必须等待这些错误之一得到修复:

    https://bugs.php.net/bug.php?id=36030

    https://bugs.php.net/bug.php?id=34972

    我目前正在探索一种通过 win32 API 防止窗口失去焦点的选项,但这对于我的需求来说似乎也不切实际。

    这是我现在使用的解决方法...

    https://gist.github.com/anonymous/80080060869f875e7214

    【讨论】:

      猜你喜欢
      • 2023-03-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-05
      • 2017-11-08
      • 1970-01-01
      • 2011-10-03
      相关资源
      最近更新 更多