WinAPI的C ++客户端读取之前检测匿名管道写(WinAPI C++ client detect

2019-07-18 14:50发布

我写一个C ++(Windows)中的客户端的控制台应用程序,从标准输入上一个匿名管道读取。 我希望能够用我的程序如下:

echo input text here | my_app.exe

和做一些与在管道的文本应用程序

要么

my_app.exe

然后使用一些默认的文本应用程序,而不是从管道输入的内部。

我现在有代码,从给出的第一种情况的标准输入管道成功读取:

#include <Windows.h>
#include <iostream>
#include <string>

#define BUFSIZE 4096

int main(int argc, const char *argv[]) {
    char char_buffer[BUFSIZE]; 
    DWORD bytes_read;
    HANDLE stdin_handle;
    BOOL continue_reading;
    unsigned int required_size;
    bool read_successful = true;

    stdin_handle = GetStdHandle(STD_INPUT_HANDLE);

    if (stdin_handle == INVALID_HANDLE_VALUE) {
        std::cout << "Error: invalid handle value!\n\n";
    } else {
        continue_reading = true;

        while (continue_reading) { 
            continue_reading = ReadFile(stdin_handle, char_buffer, BUFSIZE,
                &bytes_read, NULL); 

            if (continue_reading) {
                if (bytes_read != 0) {
                    // Output what we have read so far
                    for (unsigned int i = 0; i < bytes_read; i++) {
                        std::cout << char_buffer[i];
                    }
                } else {
                    continue_reading = false;
                }
            }
        }
    }

    return 0;
}

我知道我用匿名管道唯一的选择就是做ReadFile的读取阻塞。 如果我理解正确的话,关于我如何调用它,ReadFile的将继续从标准输入缓冲区读取,直到它检测到写操作对管(的另一端的端perhapse读取某种“写的结束”令牌?)。 我想知道是否有某种“开始写”令牌,将在缓冲区,如果事情被管道中,我可以检查标准输入之前我打电话的ReadFile的。 如果是这样的话我可能就跳过调用ReadFile和使用一些默认的文本。

如果没有办法做到这一点,我可以随时通过在表示我不应该检查管道,只是使用默认的文本(或者反过来)命令行参数,但我更喜欢做我指定的方式。

Answer 1:

它看起来像什么你真的想在这里做的是决定你是否已经有了控制台输入(在您使用默认值)与管道输入(在您使用从管道输入)。

推荐的测试,而不是直接尝试检查是否有输入准备的是:捕捉,试图嗅出是否有管道中的数据是,如果源应用程序是在生成输出慢,你的应用程序可能只是因为有ISN”做出不正确的假设科技投入尚未公布。 (这也可能是有可能的是,由于预输入,有一个用户可以在这方面准备从控制台STDIN之前您的应用程序都绕来检查,如果输入可用来读取字符键入。)

另外,请记住,这可能是有用的,以便与文件重定向,不只是管道使用您的应用程序 - 如:

myapp.exe < some_input_file

经典的方式做到这一点“交互模式,VS与重定向输入用的”使用isatty在UNIX上测试(); 幸运的是有在Windows CRT同等-看功能_isatty() ; 或使用GetFileType()检查FILE_TYPE_CHAR上GetStdHandle(STD_INPUT_HANDLE) -或使用说GetConsoleMode作为人头马呢,这只会在真正的控制台手柄成功。



Answer 2:

看看PeekNamedPipe() 尽管它的名字,它同时适用于命名和匿名管道。

int main(int argc, const char *argv[])
{
    char char_buffer[BUFSIZE]; 
    DWORD bytes_read;
    DWORD bytes_avail;
    DWORD dw;
    HANDLE stdin_handle;
    bool is_pipe;

    stdin_handle = GetStdHandle(STD_INPUT_HANDLE);
    is_pipe = !GetConsoleMode(stdin_handle, &dw);

    if (stdin_handle == INVALID_HANDLE_VALUE) {
        std::cout << "Error: invalid handle value!\n\n";
    } else {
        while (1) { 
            if (is_pipe) {
                if (PeekNamedPipe(stdin_handle, NULL, 0, NULL, &bytes_avail, NULL)) {
                    if (bytes_avail == 0) {
                        Sleep(100);
                        continue;
                    }
                }
            }

            if (!ReadFile(stdin_handle, char_buffer, min(bytes_avail, BUFSIZE), &bytes_read, NULL)) {
                break; 
            }

            if (bytes_read == 0) {
                break;
            }

            // Output what we have read so far
            for (unsigned int i = 0; i < bytes_read; i++) {
                std::cout << char_buffer[i];
            }
        }
    }

    return 0;
}


Answer 3:

而使用第二个线程,即不同步的ReadFile调用这也适用于无重叠I / O。 然后,主线程等待的任意时间量,其作用像上面...

希望这可以帮助...



文章来源: WinAPI C++ client detect write on anonymous pipe before reading