对于使用命名管道和I/O完成端口检测客户端断开连接的正确方法,我有一个疑问。我们有一个服务器,它使用stdin/stdout重定向到命名管道来创建子进程。管道被打开,OVERLAPPED。
我们已经看到,在客户机发出CreateFile()之后,I/O完成端口接收到一个lpNumberOfBytes为零的包--这非常有效地表示来自客户端的连接。但是,检测子进程关闭了它的stdin/stdout并退出时不会产生类似的事件。
我们提出了两种方法来检测指定的管道断开;
1)定期轮询子进程的进程句柄,以检测进程何时结束,
或
2)创建一个单独的线程,该线程在子进程的句柄上阻塞WaitForSingleObject(),当子进程发出信号时,进程已经结束,然后使用预先安排好的COMPLETION_KEY将PostQueuedCompletionStatus()生成到I/O完成端口。
这两件事都不是很难--但我想确保我没有错过一些显而易见的东西。是否有人在与IOCP相关的命名管道已关闭时得到通知?
发布于 2016-02-04 15:49:32
好的,我发现了IOCP为什么不传送断开的数据包,这与我如何测试这个问题有关。我们开发了一个统一的线束,我们的单元测试同时充当服务器和客户端。当子进程结束时,子进程的写管句柄仍在unittest中打开,因此IOCP没有解除阻塞任何处理程序线程。
要有效运行管道服务器,需要在该线程中创建一个新线程,以完成连接到管道、创建子进程和等待进程结束的工作。子进程结束后,然后关闭管道句柄,这将导致IOCP在lpNumberOfBytes设置为零的情况下传递一个排队列数据包。
下面是我们如何从用_beginthread()创建的线程中实现这一点的示例。
void __cdecl childproc(void* p) {
TCHAR* pipename = (TCHAR*)p;
/* make sure pipe handle is "inheritable" */
SECURITY_ATTRIBUTES sattr;
sattr.nLength = sizeof(SECURITY_ATTRIBUTES);
sattr.bInheritHandle = TRUE;
sattr.lpSecurityDescriptor = NULL;
HANDLE pipe = ::CreateFile(
pipename,
GENERIC_READ | GENERIC_WRITE,
0,
&sattr,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (pipe == INVALID_HANDLE_VALUE) {
_tprintf(_T("connect to named pipe failed %ld\n", GetLastError());
_endthread();
}
/* redirect stdin/stdout/stderr to pipe */
PROCESS_INFORMATION procinfo;
STARTUPINFO startinfo;
memset(&procinfo, 0, sizeof(procinfo));
memset(&startinfo, 0, sizeof(startinfo));
startinfo.cb = sizeof(startinfo);
startinfo.hStdError = pipe;
startinfo.hStdOutput = pipe;
startinfo.hStdInput = pipe;
startinfo.dwFlags |= STARTF_USESTDHANDLES;
/* create child to do a simple "cmd.exe /c dir" */
DWORD rc = ::CreateProcess(
_T("C:\\Windows\\System32\\cmd.exe"),
_T("C:\\Windows\\System32\\cmd.exe /C dir"),
NULL,
NULL,
TRUE,
0,
NULL,
NULL,
&startinfo,
&procinfo);
if (rc == 0) {
_tprintf(_T("cannot create child process: %ld\n"), GetLastError());
_endthread();
}
if (::WaitForSingleObject(procinfo.hProcess, INFINITE) != WAIT_OBJECT_0) {
_tprintf(_T("error waiting for child to end: %ld\n"), GetLastError());
}
/* cleanup */
::CloseHandle(procinfo.hProcess);
::CloseHandle(procinfo.hThread);
::CloseHandle(pipe);
_endthread();
}https://stackoverflow.com/questions/35190266
复制相似问题