Windows 重新连接到命名管道时出现问题

Windows 重新连接到命名管道时出现问题,windows,visual-c++,named-pipes,Windows,Visual C++,Named Pipes,我有一个命名的管道服务器和客户端。(在VC++中执行此操作) 服务器 CreateNamedPipe 连接命名管道 写文件 断开 重复2到4次 客户机 创建文件 读取文件 执行顺序如下: 服务器--CreateNamedPipe 客户端--创建文件 服务器--ConnectNamedPipe(应立即返回,因为客户端已连接) 服务器--写文件 客户端--读取文件 服务器--断开NamedPipe连接 客户端——CloseHandle 转到2 这是第一次很好地工作。但是,当客户端第二次尝试连接时,就

我有一个命名的管道服务器和客户端。(在VC++中执行此操作)

服务器

  • CreateNamedPipe
  • 连接命名管道
  • 写文件
  • 断开
  • 重复2到4次
  • 客户机

  • 创建文件
  • 读取文件
  • 执行顺序如下:

  • 服务器--CreateNamedPipe
  • 客户端--创建文件
  • 服务器--ConnectNamedPipe(应立即返回,因为客户端已连接)
  • 服务器--写文件
  • 客户端--读取文件
  • 服务器--断开NamedPipe连接
  • 客户端——CloseHandle
  • 转到2
  • 这是第一次很好地工作。但是,当客户端第二次尝试连接时,就会出现问题。当客户端在
    之前第二次尝试连接(CreateFile)时,服务器确实连接了NamedPipe(但在
    断开NamedPipe之后,),它会收到错误消息\u PIPE\u BUSY。如果客户机在服务器调用ConnectNamedPipe之后调用createfile,则该方法有效

    在名为ConnectNamedPipe的服务器之前(在断开连接NamedPipe之后),是否仍然可以连接客户端(CreateFile)

    服务器代码:

    pipe_handle.pipe = CreateNamedPipe(TEXT("\\\\.\\pipe\\testpipe1"),
                    PIPE_ACCESS_OUTBOUND |
                    FILE_FLAG_OVERLAPPED,        // read/write access
                    PIPE_TYPE_MESSAGE |           // message type pipe
                    PIPE_READMODE_MESSAGE |       // message-read mode
                    PIPE_WAIT,                    // blocking mode
                    PIPE_UNLIMITED_INSTANCES,     // max. instances
                    BUFFER_SIZE,                  // output buffer size
                    BUFFER_SIZE,                  // input buffer size
                    2000,              // client time-out
                    NULL);
    
    if (pipe_handle.pipe == INVALID_HANDLE_VALUE) {
        std::cout << "Error while creating pipe" << std::endl;
        return -1;
    }
    std::cout <<"Connecting to named pipe" << std::endl;
    
    std::cout<< "Somebody connected to named pipe" << std::endl;
    
    int ac;
    
    for (ac=0; ac<2; ac++) {
    
        char a[25];
        // Wait for some input. This helps me to start the client in other terminal.
        cin >> a;
        cout << "Connecting..." << endl;
    
        ConnectNamedPipe(pipe_handle.pipe, 0);
    
        cout << "Connect pipe returned." << endl;
    
        // Wait for some input.
        cin >> a;
        string message = "Test message";
        DWORD bytes_written;
    
        if (!WriteFile(pipe_handle.pipe, message.c_str(), message.size(),
                       &bytes_written, NULL)) {
    
            DWORD er = GetLastError();
            char errs[200];
            sprintf(errs, "Error : %ld", er);
            std::cout << "Error communicating to client.";
            std::cout << errs;
        }
        std::cout << "Written to pipe";
        FlushFileBuffers(pipe_handle.pipe);
        if (!DisconnectNamedPipe(pipe_handle.pipe)) {
            std::cout << "Disconnect failed"<< GetLastError() << endl;
        } else {
            std::cout << "Disconnect successful"<<endl;
        }
    }
    
    pipe\u handle.pipe=CreateNamedPipe(文本(“\\\\\\.\\pipe\\testpipe1”),
    管道进出口|
    文件\u标志\u重叠,//读/写访问
    PIPE_TYPE_MESSAGE |//消息类型PIPE
    管道读取模式消息读取模式
    管道\u等待,//阻塞模式
    管道\无限\实例,//最大实例数
    缓冲区大小,//输出缓冲区大小
    缓冲区大小,//输入缓冲区大小
    2000,//客户端超时
    无效);
    if(pipe\u handle.pipe==无效的\u handle\u值){
    
    std::cout如果在客户端的CreateFile()调用中出现错误\u PIPE\u BUSY,则需要调用WaitNamedPipe(),然后在它返回时重试。如果WaitNamedPipe()返回的值为零,则意味着它在管道不可用的情况下超时。如果将NMPWAIT\u WAIT\u FOREVER作为超时传递,则永远不会出现这种情况

    您还需要记住,在WaitNamedPipe()返回和您调用CreateFile()之间,管道可能会再次变得繁忙;因此,您需要在循环中执行此操作。如下所示:

    while (true)
    {
        hPipe = CreateFile(pipeName,
                           GENERIC_READ | GENERIC_WRITE,
                           0,
                           0,
                           OPEN_EXISTING,
                           FILE_ATTRIBUTE_NORMAL,
                           0);
        if (hPipe == INVALID_HANDLE_VALUE)
        {
            if (GetLastError() == ERROR_PIPE_BUSY)
            {
                if (!WaitNamedPipe(pipeName, NMPWAIT_USE_DEFAULT_WAIT))
                    continue;   // timeout, try again
            }
            else
                return false;   // error
        }
        else
            break;   // success
    }
    
    编辑:

    我简化了你的代码,现在它工作得很好。服务器和客户端都可以工作

    服务器:

    #include <windows.h>
    #include <stdio.h>
    
    int main(void)
    {
        HANDLE pipe;
        const DWORD BUFFER_SIZE = 1024;
    
        pipe = CreateNamedPipe("\\\\.\\pipe\\testpipe1",
                                      PIPE_ACCESS_OUTBOUND |
                                      FILE_FLAG_OVERLAPPED,          // read/write access
                                      PIPE_TYPE_MESSAGE |             // message type pipe
                                      PIPE_READMODE_MESSAGE |         // message-read mode
                                      PIPE_WAIT,                          // blocking mode
                                      PIPE_UNLIMITED_INSTANCES,   // max. instances
                                      BUFFER_SIZE,                        // output buffer size
                                      BUFFER_SIZE,                        // input buffer size
                                      2000,                 // client time-out
                                      NULL);
    
        if (pipe == INVALID_HANDLE_VALUE)
        {
            printf("Error while creating pipe\n");
            return -1;
        }
        printf("Connecting to named pipe\n");
    
        int ac;
    
        for (ac=0; ac<2; ac++)
        {
            // Wait for some input. This helps me to start the client in other terminal.
            printf("Connecting...\n");
    
            ConnectNamedPipe(pipe, 0);
    
            printf("Connect pipe returned.\n");
    
            // Wait for some input.
            char * message = "Test message";
            DWORD bytes_written;
    
            if (!WriteFile(pipe, message, strlen(message)+1, &bytes_written, NULL))
            {
    
                DWORD er = GetLastError();
                char errs[200];
                sprintf_s(errs, "Error : %ld", er);
                printf("Error communicating to client.\n");
                printf(errs);
            }
            printf("Written to pipe\n");
            FlushFileBuffers(pipe);
            if (!DisconnectNamedPipe(pipe))
            {
                printf("Disconnect failed %d\n", GetLastError());
            }
            else
            {
                printf("Disconnect successful\n");
            }
        }
    }
    
    #include <windows.h>
    #include <stdio.h>
    
    int main(void)
    {
        HANDLE hPipe;
    
        while (1)
        {
    
            printf("Returned\n");
            hPipe = CreateFile("\\\\.\\pipe\\testpipe1",
                                    GENERIC_READ, 
                                    0,                   // no sharing 
                                    NULL,                // default security attributes
                                    OPEN_EXISTING,   // opens existing pipe 
                                    0,                // default attributes 
                                    NULL);           // no template file 
    
            // Break if the pipe handle is valid. 
    
            if (hPipe != INVALID_HANDLE_VALUE)
                break;
    
    
            // Exit if an error other than ERROR_PIPE_BUSY occurs. 
    
            if (GetLastError() != ERROR_PIPE_BUSY)
            {
                printf("Could not open pipe %d\n", GetLastError()); 
                return -1;
            }
    
            // All pipe instances are busy, so wait for sometime.
    
            if ( ! WaitNamedPipe("\\\\.\\pipe\\testpipe1", NMPWAIT_USE_DEFAULT_WAIT))
            {
                printf("Could not open pipe: wait timed out.\n"); 
            }
        }
    
    
        char *message = "hello";
        DWORD cbToWrite = (strlen(message)+1)*sizeof(message[0]);
    
        DWORD bytes_to_read = 2000;
        char * buf = reinterpret_cast<char *>(malloc(bytes_to_read));
        DWORD bytes_read;
    
        printf("Waiting for read\n");
        bytes_read = 0;
        ReadFile(hPipe, buf, bytes_to_read, &bytes_read, 0);
    
        if (bytes_read <= 0)
        {
            printf("ReadFile from pipe failed. GLE \n"); 
        }
        else
            printf("Read %d bytes: %s\n", bytes_read, buf);
    
        CloseHandle(hPipe);
        return 0;
    }
    
    #包括
    #包括
    内部主(空)
    {
    手柄管;
    常量DWORD缓冲区大小=1024;
    pipe=CreateNamedPipe(“\\.\\pipe\\testpipe1”,
    管道进出口|
    文件\u标志\u重叠,//读/写访问
    PIPE_TYPE_MESSAGE |//消息类型PIPE
    管道读取模式消息读取模式
    管道\u等待,//阻塞模式
    管道\无限\实例,//最大实例数
    缓冲区大小,//输出缓冲区大小
    缓冲区大小,//输入缓冲区大小
    2000,//客户端超时
    无效);
    if(管道==无效的\u句柄\u值)
    {
    printf(“创建管道时出错\n”);
    返回-1;
    }
    printf(“连接到命名管道\n”);
    int ac;
    
    对于服务器端的(ac=0;ac),当您决定断开连接时,必须使用链:

    1) 闭柄(管)

    2) 断开命名管道(管道)


    感谢您的回复。我尝试了这段代码,但客户端一直出现错误\u PIPE\u BUSY。一旦服务器调用ConnectNamedPipe(),客户端就能够成功地创建文件()没有任何错误。非常感谢您修改我的代码。但我希望客户端能够在服务器调用ConnectNamedPipe之前连接到管道。当有数据要发送到客户端时,服务器应该连接并写入。这与正常约定相反。正常约定是服务器将调用connect并等待客户端要连接,但我希望客户端先连接,然后等待服务器连接。要在下一个注释中继续…根据,客户端应该可以在服务器之前连接。在我的示例中,服务器创建管道,客户端连接到管道,服务器连接到管道,它们交换数据,客户端关闭句柄,服务器调用DisconnectNamedPipe。这适用于第一次迭代,但对于第二次迭代,当客户端在服务器连接(ConnectNamedPipe)之前尝试连接(CreateFile)时,即使在等待(WaitNamedPipe)之后,也会出现错误\u PIPE\u BUSY它得到错误\命名\管道。只有在服务器调用ConnectNamedPipe后,它才会成功。但我希望它能在之前成功。希望我能够传达这个问题。再次感谢您的时间。编辑:上述注释中的第二次==第二次迭代。在这种情况下,您需要做的是在调用DisconnectNamedPipe后关闭管道。然后您可以立即y重新创建管道。我在修改后的示例中尝试了这一点,它工作正常。
    #include <windows.h>
    #include <stdio.h>
    
    int main(void)
    {
        HANDLE hPipe;
    
        while (1)
        {
    
            printf("Returned\n");
            hPipe = CreateFile("\\\\.\\pipe\\testpipe1",
                                    GENERIC_READ, 
                                    0,                   // no sharing 
                                    NULL,                // default security attributes
                                    OPEN_EXISTING,   // opens existing pipe 
                                    0,                // default attributes 
                                    NULL);           // no template file 
    
            // Break if the pipe handle is valid. 
    
            if (hPipe != INVALID_HANDLE_VALUE)
                break;
    
    
            // Exit if an error other than ERROR_PIPE_BUSY occurs. 
    
            if (GetLastError() != ERROR_PIPE_BUSY)
            {
                printf("Could not open pipe %d\n", GetLastError()); 
                return -1;
            }
    
            // All pipe instances are busy, so wait for sometime.
    
            if ( ! WaitNamedPipe("\\\\.\\pipe\\testpipe1", NMPWAIT_USE_DEFAULT_WAIT))
            {
                printf("Could not open pipe: wait timed out.\n"); 
            }
        }
    
    
        char *message = "hello";
        DWORD cbToWrite = (strlen(message)+1)*sizeof(message[0]);
    
        DWORD bytes_to_read = 2000;
        char * buf = reinterpret_cast<char *>(malloc(bytes_to_read));
        DWORD bytes_read;
    
        printf("Waiting for read\n");
        bytes_read = 0;
        ReadFile(hPipe, buf, bytes_to_read, &bytes_read, 0);
    
        if (bytes_read <= 0)
        {
            printf("ReadFile from pipe failed. GLE \n"); 
        }
        else
            printf("Read %d bytes: %s\n", bytes_read, buf);
    
        CloseHandle(hPipe);
        return 0;
    }