当cmd.exe失去焦点时,为什么STDIN上的stream_select变为阻塞? [英] Why stream_select on STDIN becomes blocking when cmd.exe loses focus?

查看:125
本文介绍了当cmd.exe失去焦点时,为什么STDIN上的stream_select变为阻塞?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

目标:在cmd中运行一个PHP文件,脚本循环执行x次,并在每次迭代时检查用户是否输入了任何输入( STDIN >),如果有的话-暂停循环直到用户按下Enter键,然后打印出输入内容并继续进行迭代.

Goal: run a PHP file in cmd, script loops x times and on every iteration checks to see if user has entered any input (stream_select() with STDIN) and if so - pauses the loop until the user hits enter, then prints out the input and continues with iteration.

问题:只要cmd.exe窗口处于焦点位置,脚本就可以完美运行-当我单击另一个窗口时,脚本在stream_select处暂停,直到我将cmd窗口重新聚焦并发送一些内容后,脚本才继续运行输入(只需按Enter键即可完成操作).没有错误.

Problem: Script runs perfectly as long as cmd.exe window is in focus - when I click on another window the script pauses at stream_select and doesn't continue until I but the cmd window back in focus and send it some input (a simple enter key press would do the trick). No errors.

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

Question: why does losing focus on cmd affect stream_select and block the loop? ...and is there a workaround? (e.g. is it possible to check if the current cmd window is in focus?)

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

Code example, used cmd php script.php in working directory.

<?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--;    

}

我没有运气尝试过的事情:

Things I have tried with no luck:

  • fopenfclose移动到循环之外
  • ignore_user_abort(1);
  • stream_set_blocking($stream, 0);
  • null0stream_select()
  • tv_sectv_usec参数的更高值
  • 检查 connection_aborted() connection_status()
  • moving fopen and fclose outside the loop
  • ignore_user_abort(1);
  • stream_set_blocking($stream, 0);
  • null, 0 and higher values for both tv_sec and tv_usec params of stream_select()
  • checking for connection_aborted() and connection_status()

环境:Windows 7,适用于Windows的XAMPP,PHP 5.4.19(cli),Zend Engine v2.4.0

Environment: Windows 7, XAMPP for windows, PHP 5.4.19 (cli), Zend Engine v2.4.0

推荐答案

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

I think the problem is because stream_select() will also return 1 for STDIN when the stream receives EOL, which is what I think happens when cmd loses focus.

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

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

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数组将保持不变,并且您应该从每个索引中读取.

When focus is not lost and no input is given, stream_select returns 0 and the $read array passed in is emptied by reference. When focus is lost OR when input is given, the $read array remains intact and you are expected to read from each index.

但是,这使我们的窗口用户处于糟糕的境地,因为我们没有一种方法可以使用stream_get_(contents | line)或fread或fgets非阻塞地读取零长度的字符串.而且由于我们无法区分失去焦点和提供实际数据,所以我相信我们必须等待以下错误之一得到解决:

But that leaves us window's users in a bad situation because we don't have a way to non-blockingly read that zero length string with stream_get_(contents|line) or fread or fgets. And since we cannot differentiate between losing focus and supplying actual data I believe we have to wait for one of these bugs to get fixed:

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

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

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

I'm currently exploring an option to prevent the window from losing focus via the win32 API, but that looks impractical for even my needs.

这是我目前正在使用的解决方法...

Here is the workaround I'm using for now...

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

这篇关于当cmd.exe失去焦点时,为什么STDIN上的stream_select变为阻塞?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆