Windows:如何让子进程在不关闭输入匿名管道的情况下读取它
Windows: how can I let the child process read the input anonymous pipe without closing it?
根据主题,我正在尝试开发一个简单的管道父/子程序。该程序的主要目的是保持子进程处于活动状态,并使用std::cin
和std::cout
在父/子进程之间进行通信。
在Linux上,所有这些都运行良好。
在Windows上,我一直在遵循这里的例子,与Linux有一个特殊的区别:必须调用
CloseHandle(g_hChildStd_IN_Wr)
写入子管道并冲洗它。这有关闭管道的副作用,从而终止我与子进程的连接。
我也尝试使用FlushFileBuffers,但它不起作用。
知道如何在不关闭匿名管道的情况下刷新缓冲区吗?
父进程和子进程的以下源。
如果父进程的代码基本上是上面示例中的代码:
// IN_Wr_ is initialized as below with bInheritHandle=TRUE
::CreatePipe(&IN_Rd_, &IN_Wr_, &saAttr, 0);
// and
::SetHandleInformation(IN_Wr_, HANDLE_FLAG_INHERIT, 0)
// When I spawn the child process I do
STARTUPINFO siStartInfo = {0};
siStartInfo.cb = sizeof(STARTUPINFO);
siStartInfo.hStdError = INVALID_HANDLE_VALUE;
siStartInfo.hStdOutput = OUT_Wr_;
siStartInfo.hStdInput = IN_Rd_;
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
...
// then in order to write to std::cin
const DWORD reqSz = static_cast<DWORD>(std::strlen(request));
DWORD written = 0;
while(true) {
DWORD curWritten = 0;
if(!WriteFile(IN_Wr_, request + written, reqSz-written, &curWritten, NULL))
throw std::runtime_error("Error on WriteFile");
written += curWritten;
if(written == reqSz) {
// all written, done
break;
}
}
::FlushFileBuffers(IN_Wr_);
// only when I do this CloseHandle then the child process
// is able to read data
::CloseHandle(IN_Wr_);
此子代码是一个简单的 Echo 服务器,如下所示:
buif[2048+1];
while(std::cin) {
std::cin.read(buf, 2048);
const auto rb = std::cin.gcount();
buf[rb] = ' ';
std::cout << buf << std::endl; // this does flush
}
这是你的问题:
std::cin.read(buf, 2048);
它正在执行您要求的操作:等到它读取 2048 个字符或到达文件末尾。 您不会发送 2048 个字符,因此在服务器关闭管道之前不会发生任何操作,在此上下文中,管道计为文件末尾。
相反,您应该使用类似 getline(s, 2048, ' ')
的东西,当它看到空字符时将停止读取。 (当然,您需要修改发送方,以便它在字符串末尾写入该空字符。
或者,您可以使用本机API:ReadFile
具有您似乎想要的语义。 理想情况下,您将使用消息模式管道,该管道正是为此类用途而设计的。
这里的文章可能会有所帮助:https://support.microsoft.com/en-us/kb/190351。它有一个关于使用 printf 将数据发送到重定向管道时的刷新问题的部分,这似乎是在您的情况下完成的。建议的解决方案是使用 fflush(NULL) 刷新 C 运行时 IO 缓冲区。
看起来问题是 std::cin::read
(甚至fread(..., ..., ..., stdin)
)的 MSFT 实现。如果而不是依赖:
// C++ API
while(std::cin) {
std::cin.read(buf, 2048);
...
// or also "C" API
int rb = 0;
while(0 < (rb = fread(buf, 2048, 1, stdin))) {
...
我愿意
// Low level Win32 "C" API
while(::ReadFile(hStdin, buf, 2048, &rb, 0)) {
...
// or also low level unix-like "C" API
int rb = 0;
while(0 < (rb = _read(0, buf, 2048))) {
...
上面的示例工作正常(有趣的是,甚至不需要调用 FlushFileBuffers)。
- C++外部程序的输入和输出管道
- 当使用带有stdin和stdout重定向的双进程管道时,如何避免stdin上的重复输入
- 在断点而不是最初以 GDB 发送管道输入
- 我应该使用 DeviceContext 函数在管道中循环输入还是通过创建来输入
- C++ microshell,输入一个命令并使用fork(),dup(),pipe()将其通过管道传输到进程。只是我没有得到我想要的结果
- 将PowerShell.exe的输入和输出重定向到C 中的管道
- 防止在管道中输入数据时退出
- 从管道读取输入时出现scanf问题
- 通过管道将自定义标准输入传输到C++中的系统调用
- Windows:如何让子进程在不关闭输入匿名管道的情况下读取它
- 通过管道将输入从 Bash 传输到 C++ cin 中
- 执行控制台程序,写入标准输入并使用管道读取结果
- 将输入管道传输到c++程序中以在Visual Studio中进行调试
- c++getline似乎无法识别通过管道传输到stdin的输入中的换行符
- 正在读取管道输入
- 输入/输出管道
- 重定向程序输出作为输入管道不工作
- TBB管道库的输入过滤器指南
- 从C++中的管道获取连续输入
- 打开通向程序的管道并将其放入标准输入