根据主题,我试图开发一个简单的管道父母/子女计划。
此程序的主要目的是使子进程保持活动状态,并使用std::cin
和std::cout
在父/子进程之间进行通信。
在Linux上,所有这些都很有效。
在Windows上,我一直在关注示例here,并且与Linux有一个独特的区别:一个必须调用
CloseHandle(g_hChildStd_IN_Wr)
写入子管道并将其冲洗。这会产生关闭管道的副作用,从而终止我的 in-connection 到子进程。
我也曾尝试使用FlushFileBuffers,但它无法正常使用。
任何想法如何刷新缓冲区而不必关闭匿名管道?
以下 Parent 和 Child 进程的来源 如果 parent 进程的代码基本上是上例中的代码:
// 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] = '\0';
std::cout << buf << std::endl; // this does flush
}
答案 0 :(得分:1)
这是你的问题:
std::cin.read(buf, 2048);
它正在按照您的要求进行操作:等待它读取2048个字符或到达文件末尾。您没有发送2048个字符,因此在服务器关闭管道之前不会发生任何事情,在此上下文中将其视为文件的结尾。
相反,你应该使用像getline(s, 2048, '\0')
这样的东西,它会在看到空字符时停止阅读。 (当然,您需要修改发件人,以便在字符串末尾写入该空字符。)
或者,您可以使用本机API:ReadFile
具有您似乎想要的语义。理想情况下,您将使用消息模式管道,该管道专为此类用途而设计。
答案 1 :(得分:0)
这里的文章可能会有所帮助:https://support.microsoft.com/en-us/kb/190351。当printf用于将数据发送到重定向管道时,它有一个关于刷新问题的部分,这似乎是在您的情况下完成的。建议的解决方案是使用fflush(NULL)来刷新C运行时IO缓冲区。
答案 2 :(得分:0)
问题似乎是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的调用甚至不需要)。