【问题标题】:WinAPI C++ client detect write on anonymous pipe before readingWinAPI C++ 客户端在读取之前检测匿名管道上的写入
【发布时间】:2013-01-23 23:32:48
【问题描述】:

我正在编写一个从 STDIN 上的匿名管道读取的 C++ (Windows) 客户端控制台应用程序。我希望能够按如下方式使用我的程序:

echo input text here | my_app.exe

并在应用程序中使用管道输入的文本执行某些操作

my_app.exe

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

鉴于第一种情况,我目前的代码可以从 STDIN 上的管道成功读取:

#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 将继续从 STDIN 上的缓冲区读取,直到它检测到管道另一端的写操作结束(也许读取某种“写结束”令牌??)。我想知道是否有某种“开始写入”令牌将在缓冲区中,如果我可以在其中检查 STDIN BEFORE 我调用 ReadFile。如果是这种情况,我可以跳过调用 ReadFile 并使用一些默认文本。

如果没有办法做到这一点,我总是可以传入一个命令行参数,表示我不应该检查管道而只使用默认文本(或其他方式),但我更喜欢按照我指定的方式进行。

【问题讨论】:

    标签: winapi visual-c++ pipe


    【解决方案1】:

    看看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;
    }
    

    【讨论】:

    • +1 以获得有用的答案。我将 BrendanMcK 的答案标记为正确,因为它显示了一种更有效的方法(我真的只需要调用 GetConsoleMode 并检查返回值),但你的答案也为我清除了一些东西。谢谢!
    【解决方案2】:

    看起来您真正想要做的是确定您是否有控制台输入(使用默认值)与管道输入(使用管道输入)。

    建议直接测试而不是尝试检查是否有输入准备好:尝试嗅探管道中是否有数据的问题是,如果源应用程序生成输出的速度很慢,您的应用程序可能会做出不正确的假设,因为没有可用的输入。 (也有可能,由于预先输入,在您的应用开始检查输入是否可用之前,用户可能已经输入了准备从控制台 STDIN 读取的区域。)

    另外,请记住,允许您的应用与文件重定向一起使用可能会很有用,而不仅仅是管道 - 例如:

    myapp.exe < some_input_file
    

    在 unix 上执行此“交互模式,与使用重定向输入”测试的经典方法是使用 isatty();幸运的是,在 Windows CRT 中有一个等价物 - 请参阅 function _isatty();或使用 GetFileType() 检查 GetStdHandle(STD_INPUT_HANDLE) 上的 FILE_TYPE_CHAR - 或像 Remy 那样使用 GetConsoleMode,这只会在真正的控制台句柄上成功。

    【讨论】:

    • 太棒了,谢谢!对 GetConsoleMode 的单一调用正是我想要的。
    【解决方案3】:

    这在使用第二个线程时也可以在没有重叠 I/O 的情况下工作,该线程执行同步 ReadFile 调用。然后主线程等待任意时间并像上面一样操作......

    希望这会有所帮助...

    【讨论】:

    • 这可行,但不是我真正想要的。我宁愿只检查输入参数,也不愿为此添加单独的线程。不过谢谢!
    猜你喜欢
    • 2014-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-03
    • 2011-03-14
    相关资源
    最近更新 更多