php之当 cmd.exe 失去焦点时,为什么 STDIN 上的 stream_select 会阻塞

wuhuacong 阅读:29 2024-09-07 23:24:14 评论:0

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

问题:只要 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 以及 stream_select() 的 tv_sectv_usec 参数的更高值
  • 正在检查 connection_aborted()connection_status()

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

请您参考如下方法:

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

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

in particular, a stream resource is also ready on end-of-file, in which case an fread() will return a zero length string

当焦点未丢失且未给出输入时,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


标签:PHP
声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

关注我们

一个IT知识分享的公众号