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

时间:2011-08-05 18:52:28

标签: windows visual-c++ named-pipes

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

服务器可以

  1. CreateNamedPipe时
  2. ConnectNamedPipe
  3. WriteFile的
  4. 断开
  5. 从2到4重复
  6. 客户

    1. 的CreateFile
    2. ReadFile的
    3. 执行顺序如下,

      1. 服务器 - CreateNamedPipe
      2. 客户端 - CreateFile
      3. 服务器 - ConnectNamedPipe(应在客户端已连接时立即返回)
      4. 服务器 - WriteFile
      5. 客户 - ReadFile
      6. 服务器 - DisconnectNamedPipe
      7. 客户 - CloseHandle
      8. 转到2
      9. 这是第一次正常工作。但是,当客户端尝试第二次连接时会出现问题。当客户端第二次尝试连接(CreateFile)之前服务器执行ConnectNamedPipe(但 disconnectnamedpipe之后)时,它会获得ERROR_PIPE_BUSY。如果客户端在服务器调用ConnectNamedPipe后调用createfile,则它可以工作。

        无论如何我可以在服务器调用ConnectNamedPipe之前连接客户端(CreateFile)(在DisconnectNamedPipe之后)?

        服务器代码:

        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;
            }
        }
        

        客户代码:

        while (1) { 
        
            std::cout << "Returned" << std::endl;
            hPipe = CreateFile( 
                      lpszPipename,   // pipe name 
                      GENERIC_READ, 
                      0,              // no sharing 
                      NULL,           // default security attributes
                      OPEN_EXISTING,  // opens existing pipe 
                      FILE_FLAG_OVERLAPPED,              // 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) {
                std::cout<< "Could not open pipe " << GetLastError() << std::endl; 
                return -1;
            }
        
            // All pipe instances are busy, so wait for sometime.
        
            if ( ! WaitNamedPipe(lpszPipename, NMPWAIT_USE_DEFAULT_WAIT)) { 
                std::cout<<  "Could not open pipe: wait timed out." << std::endl; 
            } 
        }
        
        OVERLAPPED ol1;
        
        memset(&ol1, 0, sizeof(ol1));
        ol1.Offset = 0;
        ol1.OffsetHigh = 0;
        ol1.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
        
        HANDLE events[1];
        events[0] = ol1.hEvent;
        cbToWrite = (lstrlen(message)+1)*sizeof(TCHAR);
        
        DWORD bytes_to_read = 2000;
        char * buf = reinterpret_cast<char *>(malloc(bytes_to_read));
        DWORD bytes_read;
        
        std::cout << "Waiting for read" << std::endl;
        bool a = ReadFile(hPipe, buf, bytes_to_read, &bytes_read, &ol1);
        
        
        if ( ! fSuccess) {
            std::cout << "WriteFile to pipe failed. GLE " << GetLastError() << std::endl; 
        }
        std::cout << "Waiting for multiple objects" << std::endl;
        WaitForMultipleObjects(1, events, FALSE, INFINITE);
        std::cout << "multiple objects returned" << std::endl;
        printf("\nMessage sent to server");
        CancelIo(hPipe);
        CloseHandle(hPipe);
        

2 个答案:

答案 0 :(得分:8)

如果在客户端的CreateFile()调用上获得ERROR_PIPE_BUSY,则需要调用WaitNamedPipe(),然后在返回时重试。如果从WaitNamedPipe()返回零,这意味着它在没有管道可用的情况下超时。如果你将NMPWAIT_WAIT_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;
}

答案 1 :(得分:-2)

在服务器端,当您决定断开连接时,必须使用chain:

  

1)CloseHandle(Pipe);

     

2)DisconnectNamedPipe(Pipe);