【问题标题】:ReadFile from a subprocess keeps returning same data来自子进程的 ReadFile 不断返回相同的数据
【发布时间】:2016-10-06 03:54:06
【问题描述】:

我正在尝试创建一个子进程并使用 Windows 管道与它异步通信,然后在子进程生成输出时将其输出重定向到主进程的 cout。 这是我现在的代码:

HANDLE hWriteOUT, hReadOUT, hWriteIN, hReadIN;
SECURITY_ATTRIBUTES saPipe = { 0 };
PROCESS_INFORMATION procInfo = { 0 };
STARTUPINFO procSi;
DWORD dwWritten, dwRead;
int bufsize = 6000;
char buf[6000];
saPipe.nLength = sizeof(SECURITY_ATTRIBUTES);
saPipe.bInheritHandle = TRUE;
saPipe.lpSecurityDescriptor = NULL;
CreatePipe(&hReadOUT, &hWriteOUT, &saPipe, 0);
SetHandleInformation(hReadOUT, HANDLE_FLAG_INHERIT, 0);
CreatePipe(&hReadIN, &hWriteIN, &saPipe, 0);
SetHandleInformation(hWriteIN, HANDLE_FLAG_INHERIT, 0);

ZeroMemory(&procSi, sizeof(STARTUPINFO));
procSi.cb = sizeof(STARTUPINFO);
procSi.hStdError = hWriteOUT;
procSi.hStdOutput = hWriteOUT;
procSi.hStdInput = hReadIN;
procSi.dwFlags |= STARTF_USESTDHANDLES;
CreateProcess(
        NULL,
        (LPSTR) "app.exe",
        NULL, NULL, TRUE, 0, NULL, NULL, &procSi, &procInfo);

WriteFile(hWriteIN, "go movetime 1000\n", strlen("go movetime 1000\n"),
        &dwWritten, NULL);

auto start = clock();
auto seconds = 1.5;;
do {
    Sleep(500);
    cout << "cycle..." << endl;
    buf[0]=char(NULL);
    ReadFile(hReadOUT, buf, bufsize, &dwRead, NULL);
    cout << buf;
    //loop for 1.5 seconds = 3 cycles
} while ((double(clock() - start) / ((double) CLOCKS_PER_SEC)) < seconds);

问题在于连续读取似乎没有按顺序访问信息。如果我简化输出,那么不要像这样:

循环... 1 2 3 循环... 4 5 6 循环... 7 8 完成!

我看到了类似的东西:

循环... 1 2 3 循环... 4 2 3 循环... 8 完毕! 4

输出的某些部分丢失,有些被跳过! 如果我摆脱 for 循环并在更长的延迟后只读取一次,我确实会得到预期的结果。

我假设我的子进程不断将内容转储到管道中的事实使 ReadFile 应该保留的偏移量无效。 解决办法是什么?

【问题讨论】:

    标签: c++ windows asynchronous process pipe


    【解决方案1】:

    ReadFile 会读取直到您传入的 bufsize 参数的字节。它不会在末尾放置一个零字节,因此您不能只将缓冲区视为以空字符结尾的字符串。

    它返回第四个参数中读取的字节数(在您的情况下为dwRead)。但是,您没有使用函数设置到该变量中的值。

    这意味着当您在循环中第二次打印出缓冲区时,如果ReadFile 调用仅读取一个字节,cout 语句仍将打印上一次调用的缓冲区中的值。这就是为什么你得到“4 2 3”的原因,因为 readfile 刚刚用 4 替换了 1。

    解决此问题的一种方法是在缓冲区末尾留出一些空间用于 NULL 字节,然后将 NULL 字节设置到缓冲区中,以便cout 知道何时停止。 (注意:将第一个字节设置为 NULL 不起作用,因为这是 ReadFile 将写入的第一件事)。

    类似:

    ReadFile(hReadOUT, buf, bufsize - 1, &dwRead, NULL);
    buf[dwRead] = '\0';
    cout << buf;
    

    注意 bufsize 后面的 - 1,否则你可能会不走运并读取 6000 字节并尝试将数组的 6001 字节设置为 \0,这将导致缓冲区溢出。

    您还可以进行一些健全性检查,以确保 dwRead 为负数且小于 bufsize。

    还有其他方法可以解决这个问题(将您检索到的确切字节数附加到一个字符串中,然后在最后打印出来。或者您可以在调用 ReadFile 之前将缓冲区完全归零,但这将是矫枉过正)。

    我不确定您为什么会因为这个问题而错过 5、6 和 7,但它可能是相关的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-08-28
      • 1970-01-01
      • 2010-09-22
      • 2015-03-02
      • 1970-01-01
      • 2015-05-18
      • 1970-01-01
      • 2017-02-12
      相关资源
      最近更新 更多