检查 Win32 文件流的可用输入 [英] Checking Win32 file streams for available input

查看:16
本文介绍了检查 Win32 文件流的可用输入的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个简单的隧道程序,需要同时阻塞标准输入和套接字.我目前有一个看起来像这样的程序(省略了错误处理和样板内容):

I have a simple tunnel program that needs to simultaneously block on standard input and a socket. I currently have a program that looks like this (error handling and boiler plate stuff omitted):

HANDLE host = GetStdHandle(STD_INPUT_HANDLE);
SOCKET peer = ...; // socket(), connect()...

WSAEVENT gate = WSACreateEvent();
OVERLAPPED xfer;
ZeroMemory(&xfer, sizeof(xfer));
xfer.hEvent = gate;
WSABUF pbuf = ...; // allocate memory, set size.

// start an asynchronous transfer.
WSARecv(peer, &pbuf, 1, 0, &xfer, 0);
while ( running )
{
    // wait until standard input has available data or the event
    // is signaled to inform that socket read operation completed.
    HANDLE handles[2] = { host, gate };
    const DWORD which = WaitForMultipleObjects
        (2, handles, FALSE, INFINITE) - WAIT_OBJECT_0;

    if (which == 0)
    {
        // read stuff from standard input.
        ReadFile(host, ...);
        // process stuff received from host.
        // ...
    }
    if (which == 1)
    {
        // process stuff received from peer.
        // ...
        // start another asynchronous transfer.
        WSARecv(peer, &pbuf, 1, 0, &xfer, 0);
    }
}

这个程序就像一个魅力,我可以毫不费力地通过这个隧道程序传输东西.问题是它有一个微妙的错误.

The program works like a charm, I can transfer stuff through this tunnel program without a hitch. The thing is that it has a subtle bug.

如果我从 cmd.exe 以交互模式启动这个程序并且标准输入连接到键盘,按下一个不产生输入的键(例如 Ctrlkey) 使该程序阻塞并忽略套接字上接收到的数据.我设法意识到这是因为按下 any 键表示标准输入句柄和 WaitForMultipleObjects() 返回.正如预期的那样,控制进入 if (which == 0) 块和对 ReadFile() 块的调用,因为没有可用的输入.

If I start this program in interactive mode from cmd.exe and standard input is attached to the keyboard, pressing a key that does not produce input (e.g. the Ctrl key) makes this program block and ignore data received on the socket. I managed to realize that this is because pressing any key signals the standard input handle and WaitForMultipleObjects() returns. As expected, control enters the if (which == 0) block and the call to ReadFile() blocks because there is no input available.

有没有办法检测 Win32 流上有多少可用输入?如果是这样,我可以在调用 ReadFile() 之前使用它来检查是否有任何输入可用以避免阻塞.

Is there a means to detect how much input is available on a Win32 stream? If so, I could use this to check if any input is available before calling ReadFile() to avoid blocking.

我知道一些针对特定类型流的解决方案(特别是串行端口的 ClearCommError() 和套接字的 ioctlsocket(socket,FIONBIO,&count)),但我所知道的没有一个适用于 CONIN$ 流.

I know of a few solutions for specific types of streams (notably ClearCommError() for serial ports and ioctlsocket(socket,FIONBIO,&count) for sockets), but none that I know of works with the CONIN$ stream.

推荐答案

使用重叠 I/O.然后测试附加到 I/O 操作的事件,而不是句柄.

Use overlapped I/O. Then test the event attached to the I/O operation, instead of the handle.

对于 CONIN$,您还可以查看控制台输入 API,例如 PeekConsoleInputGetNumberOfConsoleInputEvents

For CONIN$ specifically, you might also look at the Console Input APIs, such as PeekConsoleInput and GetNumberOfConsoleInputEvents

但我真的建议尽可能使用 OVERLAPPED(背景)读取,而不是试图将 WaitForMultipleObjectsselect 一样对待.

But I really recommend using OVERLAPPED (background) reads wherever possible and not trying to treat WaitForMultipleObjects like select.

由于在重叠模式下控制台不能重叠,您最简单的选择是等待控制台句柄并使用 ReadConsoleInput(然后您必须手动处理控制序列),或者生成一个专用的同步 ReadFile 的工作线程.如果您选择一个工作线程,那么您可能希望使用重叠管道读取在该工作线程和主 I/O 循环之间连接一个管道.

Since the console can't be overlapped in overlapped mode, your simplest options are to wait on the console handle and use ReadConsoleInput (then you have to process control sequences manually), or spawn a dedicated worker thread for synchronous ReadFile. If you choose a worker thread, you may want to then connect a pipe between that worker and the main I/O loop, using overlapped pipe reads.

我从未尝试过的另一种可能性是等待控制台句柄并使用 PeekConsoleInput 来确定是调用 ReadFile 还是 ReadConsoleInput.这样,您应该能够在完成终端处理的同时获得非阻塞.OTOH,将控制序列传递给 ReadConsoleInput 可能会抑制他们应该采取的缓冲区操作操作.

Another possibility, which I've never tried, would be to wait on the console handle and use PeekConsoleInput to find out whether to call ReadFile or ReadConsoleInput. That way you should be able to get non-blocking along with the cooked terminal processing. OTOH, passing control sequences to ReadConsoleInput might inhibit the buffer-manipulation actions they were supposed to take.

如果两个流是独立处理的,或者几乎是独立处理的,那么为每个流启动一个线程可能更有意义.然后你可以使用标准输入的阻塞读取.

If the two streams are processed independently, or nearly so, it may make more sense to start a thread for each one. Then you can use a blocking read from standard input.

这篇关于检查 Win32 文件流的可用输入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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