Win32 - 从stdin读取超时 [英] Win32 - read from stdin with timeout

查看:270
本文介绍了Win32 - 从stdin读取超时的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想做一些我认为应该很简单的事情:从标准输入阻塞读取,但如果没有数据可用,在指定的时间间隔后超时。



在Unix世界中,这将是简单的select(),但是在Windows中不工作,因为stdin不是套接字。



我使用的视觉C ++为目标Win32环境。



到目前为止我试过:


  1. 使用select(如果输入不是套接字, p>


  2. 使用WaitForSingleObject(GetStdHandle(STD_INPUT_HANDLE))。 - Remy的第一个建议。如果标准输入是一个控制台(其他人报告了同样的问题),这个命令总是立即返回。


  3. 使用重叠IO并执行WaitForSingleObject (remy的第三个建议)。在这种情况下,当输入来自控制台时,读取总是似乎阻塞 - 似乎stdin不支持异步I / O。


目前我认为我唯一剩下的选择是创建一个线程,它将做一个阻塞读,然后发出一个事件,然后有另一个线程等待事件超时。

解决方案

我不得不解决类似的问题。在Windows上,它不像Linux那么容易或明显。然而,这是可能的。诀窍是Windows将控制台事件放在控制台输入事件队列中。你必须过滤掉你不关心的事件,并只处理你关心的事件(例如按键)。



进一步阅读: a href =http://msdn.microsoft.com/en-us/library/windows/desktop/ms686971%28v=vs.85%29.aspx =nofollow>请参阅Win32控制台文档



这里是一些基于套接字和stdin多路复用器工作的几个调试示例代码:

  void ProcessStdin(void)
{
INPUT_RECORD record;
DWORD numRead;
if(!ReadConsoleInput(GetStdHandle(STD_INPUT_HANDLE),& record,1,& numRead)){
// hmm处理这个错误...
return;
}

if(record.EventType!= KEY_EVENT){
//不关心其他控制台事件
return;
}

if(!record.Event.KeyEvent.bKeyDown){
//真正只关心keydown
return;
}

//如果你设置为ASCII,处理这个:
//record.Event.KeyEvent.uChar.AsciiChar

} // end ProcessStdin

int main(char argc,char * argv [])
{
HANDLE eventHandles [] = {
GetStdHandle(STD_INPUT_HANDLE)
// ...这里添加更多的句柄和/或套接字
};

DWORD result = WSAWaitForMultipleEvents(sizeof(eventHandles)/ sizeof(eventHandle [0]),
& eventHandles [0],
FALSE,
1000,
TRUE
);

switch(result){
case WSA_WAIT_TIMEOUT://没有I / O现在正在运行
break;

case WSA_WAIT_EVENT_0 + 0:// stdin在数组索引0
ProcessStdin();
break;

case WSA_WAIT_EVENT_0 + 1://数组索引处的handle / socket 1
break;

case WSA_WAIT_EVENT_0 + 2:// ...等等
break;

默认值://处理其他可能的条件
break;
} //结束切换结果
}


I'm trying to do something which I think should be simple: do a blocking read from standard input, but timing out after a specified interval if no data is available.

In the Unix world this would be simple with select() but that doesn't work in Windows because stdin isn't a socket. What's the next simplest option without creating extra threads etc?

I'm using visual C++ targeting a Win32 environment.

so far I have tried:

  1. using select (doesn't work if the input is not a socket)

  2. using WaitForSingleObject(GetStdHandle(STD_INPUT_HANDLE)). - Remy's first suggestion. This always seems to return immediately when you call it if the standard input is a console (others have reported the same problem)

  3. using overlapped IO and doing a WaitForSingleObject (remy's third suggestion). In this case the read always seems to block when the input is coming from a console - it seems that stdin does not support asynchronous I/O.

At the moment I'm thinking my only remaining option is to create a thread which will do a blocking read and then signal an event, and then have another thread which waits for the event with a timeout.

解决方案

I had to solve a similar problem. On Windows it is not as easy or obvious as Linux. It is, however, possible. The trick is that Windows places console events in the console input event queue. You've got to filter out the events you don't care about and only process those events you do care about (like key presses).

For further reading: see the Win32 console documentation

Here is some mostly-debugged sample code based on a socket and stdin multiplexer I was working on:

void ProcessStdin(void)
{
    INPUT_RECORD record;
    DWORD numRead;
    if(!ReadConsoleInput(GetStdHandle(STD_INPUT_HANDLE), &record, 1, &numRead)) {
        // hmm handle this error somehow...
        return;
    }

    if(record.EventType != KEY_EVENT) {
        // don't care about other console events
        return;
    }

    if(!record.Event.KeyEvent.bKeyDown) {
        // really only care about keydown
        return;
    }

    // if you're setup for ASCII, process this:
    //record.Event.KeyEvent.uChar.AsciiChar

} // end ProcessStdin

int main(char argc, char* argv[])
{
    HANDLE eventHandles[] = {
        GetStdHandle(STD_INPUT_HANDLE)
        // ... add more handles and/or sockets here
        };

    DWORD result = WSAWaitForMultipleEvents(sizeof(eventHandles)/sizeof(eventHandle[0]), 
        &eventHandles[0], 
        FALSE, 
        1000, 
        TRUE
        );

    switch(result) {
        case WSA_WAIT_TIMEOUT: // no I/O going on right now
            break;

        case WSA_WAIT_EVENT_0 + 0: // stdin at array index 0
            ProcessStdin();
            break;

        case WSA_WAIT_EVENT_0 + 1: // handle/socket at array index 1
            break;

        case WSA_WAIT_EVENT_0 + 2: // ... and so on
            break;

        default: // handle the other possible conditions
            break;
    } // end switch result
}

这篇关于Win32 - 从stdin读取超时的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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