首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >检测命名管道与I/O完成断开

检测命名管道与I/O完成断开
EN

Stack Overflow用户
提问于 2016-02-04 00:14:14
回答 1查看 314关注 0票数 0

对于使用命名管道和I/O完成端口检测客户端断开连接的正确方法,我有一个疑问。我们有一个服务器,它使用stdin/stdout重定向到命名管道来创建子进程。管道被打开,OVERLAPPED

我们已经看到,在客户机发出CreateFile()之后,I/O完成端口接收到一个lpNumberOfBytes为零的包--这非常有效地表示来自客户端的连接。但是,检测子进程关闭了它的stdin/stdout并退出时不会产生类似的事件。

我们提出了两种方法来检测指定的管道断开;

1)定期轮询子进程的进程句柄,以检测进程何时结束,

2)创建一个单独的线程,该线程在子进程的句柄上阻塞WaitForSingleObject(),当子进程发出信号时,进程已经结束,然后使用预先安排好的COMPLETION_KEY将PostQueuedCompletionStatus()生成到I/O完成端口。

这两件事都不是很难--但我想确保我没有错过一些显而易见的东西。是否有人在与IOCP相关的命名管道已关闭时得到通知?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-02-04 15:49:32

好的,我发现了IOCP为什么不传送断开的数据包,这与我如何测试这个问题有关。我们开发了一个统一的线束,我们的单元测试同时充当服务器和客户端。当子进程结束时,子进程的写管句柄仍在unittest中打开,因此IOCP没有解除阻塞任何处理程序线程。

要有效运行管道服务器,需要在该线程中创建一个新线程,以完成连接到管道、创建子进程和等待进程结束的工作。子进程结束后,然后关闭管道句柄,这将导致IOCP在lpNumberOfBytes设置为零的情况下传递一个排队列数据包。

下面是我们如何从用_beginthread()创建的线程中实现这一点的示例。

代码语言:javascript
复制
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();
    }
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35190266

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档