在C++中创建Windows命名管道

28
我正在尝试在C++(Windows)中创建两个进程之间的简单通信,就像Linux中的FIFO一样。
这是我的服务器:
int main()
{
    HANDLE pipe = CreateFile(TEXT("\\\\.\\pipe\\Pipe"), GENERIC_READ, 0, NULL, OPEN_EXISTING,    FILE_FLAG_OVERLAPPED, NULL);
    ConnectNamedPipe(pipe, NULL);
    while(TRUE){
        string data;
        DWORD numRead =1 ;
        ReadFile(pipe, &data, 1024, &numRead, NULL);
        cout << data << endl;

}
    CloseHandle(pipe);
    return 0;
}

这是我的客户:
int main()
{
    HANDLE pipe = CreateFile(TEXT("\\\\.\\pipe\\Pipe"), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
    ConnectNamedPipe(pipe, NULL);
    string message = "TEST";
    DWORD numWritten;
    WriteFile(pipe, message.c_str(), message.length(), &numWritten, NULL);
    return 0;
}

代码不起作用。我该如何修复它,使其像FIFO一样工作?
1个回答

81
你不能通过调用CreateFile(..)来创建一个命名管道。
看一下Microsoft Learn的管道示例。由于这些示例相当复杂,我快速编写了一个非常简单的命名管道服务器和客户端。
int main(void)
{
    HANDLE hPipe;
    char buffer[1024];
    DWORD dwRead;


    hPipe = CreateNamedPipe(TEXT("\\\\.\\pipe\\Pipe"),
                            PIPE_ACCESS_DUPLEX,
                            PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,   // FILE_FLAG_FIRST_PIPE_INSTANCE is not needed but forces CreateNamedPipe(..) to fail if the pipe already exists...
                            1,
                            1024 * 16,
                            1024 * 16,
                            NMPWAIT_USE_DEFAULT_WAIT,
                            NULL);
    while (hPipe != INVALID_HANDLE_VALUE)
    {
        if (ConnectNamedPipe(hPipe, NULL) != FALSE)   // wait for someone to connect to the pipe
        {
            while (ReadFile(hPipe, buffer, sizeof(buffer) - 1, &dwRead, NULL) != FALSE)
            {
                /* add terminating zero */
                buffer[dwRead] = '\0';

                /* do something with data in buffer */
                printf("%s", buffer);
            }
        }

        DisconnectNamedPipe(hPipe);
    }

    return 0;
}

这是客户端代码:
int main(void)
{
    HANDLE hPipe;
    DWORD dwWritten;


    hPipe = CreateFile(TEXT("\\\\.\\pipe\\Pipe"), 
                       GENERIC_READ | GENERIC_WRITE, 
                       0,
                       NULL,
                       OPEN_EXISTING,
                       0,
                       NULL);
    if (hPipe != INVALID_HANDLE_VALUE)
    {
        WriteFile(hPipe,
                  "Hello Pipe\n",
                  12,   // = length of string + terminating '\0' !!!
                  &dwWritten,
                  NULL);

        CloseHandle(hPipe);
    }

    return (0);
}

你应该将管道的名称 TEXT("\\\\.\\pipe\\Pipe") 替换为一个位于常用头文件中的 #define

1
我收到了一个错误,其中 FILE_FLAG_FIRST_PIPE_INSTANCE:'FILE_FLAG_FIRST_PIPE_INSTANCE' 在此范围内未声明,但我已经在 MSDN 上阅读过,这里不应该有任何错误。 - user3052078
1
@user3052078 我做了一些更改,现在如果客户端再次运行它就可以工作了。另请注意,如果您从客户端发送多条消息,则服务器可能使用一个单独的 ReadFile(..) 读取数据(= 客户端的 5x WriteFile!= 服务器的 5x ReadFile)。因此,如果客户端发送的字符串包含 '\0' 字符,则此示例中的简单 printf("%s",buffer); 不起作用,因为 printf 在遇到第一个 '\0' 时停止。 - Lukas Thomsen
CreateFile 在失败时会返回 INVALID_HANDLE_VALUE。而 INVALID_HANDLE_VALUE != NULL - David Heffernan
4
我来晚了,但如果CreateNamedPipe成功,外层循环将永远不会退出。即使调用了DisconnectNamedPipehPipe的值也没有改变。不过,这是一个人们可以学习的好例子。 - Doug Cuthbertson
@DougCuthbertson 没错。我把这段代码从我的一个程序中复制过来,其中我使用句柄来跳出读取循环。 - Lukas Thomsen
显示剩余10条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接