代码之家  ›  专栏  ›  技术社区  ›  user1348669

未收到C++Windows异步IO命名管道第一条消息

  •  0
  • user1348669  · 技术社区  · 9 年前

    来自的修改代码 使用重叠I/O的命名管道服务器 https://msdn.microsoft.com/en-us/library/windows/desktop/aa365603(v=vs.85).aspx

    服务器代码如下:

    #include <windows.h> 
    #include <stdio.h>
    #include <tchar.h>
    #include <strsafe.h>
    #include <iostream>
    
    #define CONNECTING_STATE 0 
    #define READING_STATE 1 
    
    #define INSTANCES 4 
    #define PIPE_TIMEOUT 5000
    #define BUFSIZE 4096
    
    typedef struct 
    { 
    OVERLAPPED oOverlap; 
    HANDLE hPipeInst; 
    TCHAR chRequest[BUFSIZE]; 
    DWORD cbRead;
    TCHAR chReply[BUFSIZE];
    DWORD cbToWrite; 
    DWORD dwState; 
    BOOL fPendingIO;
    
    } PIPEINST, *LPPIPEINST; 
    
    BOOL ConnectToNewClient(HANDLE, LPOVERLAPPED); 
    
    PIPEINST Pipe[INSTANCES]; 
    HANDLE hEvents[INSTANCES]; 
    
    int _tmain(VOID) 
    { 
    DWORD i, dwWait, cbRet, dwErr; 
    BOOL fSuccess; 
    LPTSTR lpszPipename = TEXT("\\\\.\\pipe\\mynamedpipe"); 
    
    for (i = 0; i < INSTANCES; i++) 
    { 
    
        hEvents[i] = CreateEvent( 
            NULL,    // default security attribute 
            FALSE,    // manual-reset event 
            TRUE,    // initial state = signaled 
            NULL);   // unnamed event object 
    
        if (hEvents[i] == NULL) 
        {
            printf("CreateEvent failed with %d.\n", GetLastError()); 
            return 0;
        }
    
        Pipe[i].oOverlap.hEvent = hEvents[i]; 
    
        DWORD dwOpenMode = PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED;
    
        Pipe[i].oOverlap.Offset = 0;
        Pipe[i].oOverlap.OffsetHigh = 0;
    
        Pipe[i].hPipeInst = CreateNamedPipe( 
            lpszPipename,           
            dwOpenMode,     
            PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,               
            INSTANCES,               
            BUFSIZE*sizeof(TCHAR),   
            BUFSIZE*sizeof(TCHAR),   
            PIPE_TIMEOUT,            
            NULL);                   
    
        if (Pipe[i].hPipeInst == INVALID_HANDLE_VALUE) 
        {
            printf("CreateNamedPipe failed with %d.\n", GetLastError());
            return 0;
        }
    
        BOOL rc = ConnectNamedPipe(Pipe[i].hPipeInst, &Pipe[i].oOverlap);                   // Overlapped ConnectNamedPipe should return FALSE.
        if (!rc && GetLastError() == ERROR_PIPE_CONNECTED) {
            std::cout<<"pipe connected setting event " << std::endl;
            rc = SetEvent(&Pipe[i].oOverlap.hEvent);
    
        } else if (rc || GetLastError() != ERROR_IO_PENDING) {
            std::cout<<"exiting... " << std::endl;
            rc = CloseHandle(Pipe[i].hPipeInst);
            return 0;
        }
    
    }// for INSTANCES
    
        while (1) 
        { 
            dwWait = WaitForMultipleObjects( 
                INSTANCES,    // number of event objects 
                hEvents,      // array of event objects 
                FALSE,        // does not wait for all 
                INFINITE);    // waits indefinitely 
    
            i = dwWait - WAIT_OBJECT_0;  // determines which pipe 
    
            if (i < 0 || i > (INSTANCES - 1)) 
            {
                printf("Index out of range.\n"); 
                return 0;
            }
    
            fSuccess = GetOverlappedResult( 
                Pipe[i].hPipeInst, // handle to pipe 
                &Pipe[i].oOverlap, // OVERLAPPED structure 
                &cbRet,            // bytes transferred 
                FALSE);            // do not wait 
    
            std::cout<<"GetOverlappedResult " << cbRet;
            std::cout<<" success " << fSuccess;
            std::cout<<" state " << Pipe[i].dwState;
            std::cout<<" GetLastError " << GetLastError() << std::endl;
    
    
            fSuccess = ReadFile( 
                Pipe[i].hPipeInst, 
                Pipe[i].chRequest, 
                BUFSIZE*sizeof(TCHAR), 
                &Pipe[i].cbRead, 
                &Pipe[i].oOverlap); 
    
            if(!fSuccess)
                std::wcout<<L" Error: "<< GetLastError() <<std::endl;
    
            if (fSuccess && Pipe[i].cbRead != 0) 
            { 
                Pipe[i].fPendingIO = FALSE; 
                Pipe[i].dwState = READING_STATE; 
                std::wcout<<L"Message " << Pipe[i].chRequest << std::endl;
                continue; 
            } 
    
            dwErr = GetLastError(); 
            if (! fSuccess && (dwErr == ERROR_IO_PENDING)) 
            { 
                std::cout<<"Error IO is still pending" << std::endl;
                Pipe[i].fPendingIO = TRUE; 
                continue; 
            } 
            break;
        }
    
        return 0; 
    } 
    

    客户端代码如下:

     #include <windows.h> 
     #include <stdio.h>
     #include <conio.h>
     #include <tchar.h>
     #include <string>
     #include <sstream>
     #include <time.h>
     #include <iostream>
    
     #define BUFSIZE 4096
    
    int _tmain(int argc, TCHAR *argv[]) 
    { 
    HANDLE hPipe; 
    
    TCHAR  chBuf[BUFSIZE]; 
    BOOL   fSuccess = FALSE; 
    DWORD  cbRead, cbToWrite, cbWritten, dwMode; 
    LPTSTR lpszPipename = TEXT("\\\\.\\pipe\\mynamedpipe"); 
    BOOL   rc;
    
     do {
        hPipe = CreateFileW(lpszPipename, GENERIC_WRITE, FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
        if (hPipe == INVALID_HANDLE_VALUE) {
          if (GetLastError() == ERROR_PIPE_BUSY) {
            // wait for the pipe to become available
            rc = WaitNamedPipeW(lpszPipename, NMPWAIT_USE_DEFAULT_WAIT);
            if (!rc) return false;
          } else {
            return false;
          }
        }
      } while (hPipe == INVALID_HANDLE_VALUE);
    
     dwMode = PIPE_READMODE_MESSAGE; 
       fSuccess = SetNamedPipeHandleState( 
          hPipe,    // pipe handle 
          &dwMode,  // new pipe mode 
          NULL,     // don't set maximum bytes 
          NULL);    // don't set maximum time 
       if ( ! fSuccess) 
       {
          _tprintf( TEXT("SetNamedPipeHandleState failed. GLE=%d\n"), GetLastError() ); 
          return -1;
       }
    
    //===================================================================
    
    while(1)
    {
        std::cout<<"press a key to send " << std::endl;
        _getch();
    
        fSuccess = WriteFile( 
            hPipe,                  
            "A",
            1, 
            &cbWritten,             
            NULL);
     if ( ! fSuccess) 
        {
            _tprintf( TEXT("WriteFile to pipe failed. GLE=%d\n"), GetLastError()           ); 
            return -1;
        }
    
        fSuccess = WriteFile( 
            hPipe,                  
            "B",
            1, 
            &cbWritten,             
            NULL);
     if ( ! fSuccess) 
        {
            _tprintf( TEXT("WriteFile to pipe failed. GLE=%d\n"), GetLastError()    ); 
            return -1;
        }
        //Sleep(1000);
    
        fSuccess = WriteFile( 
            hPipe,                  
            "C",
            1, 
            &cbWritten,             
            NULL);
    
     if ( ! fSuccess) 
        {
            _tprintf( TEXT("WriteFile to pipe failed. GLE=%d\n"), GetLastError()       ); 
            return -1;
        }
    
        fSuccess = WriteFile( 
            hPipe,                  
            "D",
            1, 
            &cbWritten,             
            NULL);
    
    
        if ( ! fSuccess) 
        {
            _tprintf( TEXT("WriteFile to pipe failed. GLE=%d\n"), GetLastError()    ); 
            return -1;
        }
    }// loop 
    
    
    printf("\n<End of message, press ENTER to terminate connection and exit>");
    _getch();
    
    CloseHandle(hPipe); 
    
    return 0; 
    

    }

    服务器从未接收到消息A,但B、C、D接收正常。 如果在客户端中取消注释//Sleep(1000),则只会收到B和D。

    你知道为什么会这样吗?没有休眠的服务器输出如下:

     GetOverlappedResult 0 success 1 state 0 GetLastErr
     or 997
     Error: 997
     Error IO is still pending
     GetOverlappedResult 1 success 1 state 0 GetLastErr
     or 997
     Message B
     GetOverlappedResult 1 success 1 state 1 GetLastErr
     or 997
     Message C
     GetOverlappedResult 1 success 1 state 1 GetLastErr
     or 997
     Message D
     GetOverlappedResult 1 success 1 state 1 GetLastErr
     or 997
     Error: 997
     Error IO is still pending
    
    1 回复  |  直到 9 年前
        1
  •  2
  •   Harry Johnston    9 年前

    在服务器的读取循环中,您将丢弃异步到达的任何数据。

    GetOverlappedResult()报告挂起的I/O操作完成后,缓冲区包含该操作的数据。您将忽略该数据并向同一缓冲区发出新的读取操作。

    获得任何消息的唯一原因是(在大多数情况下)所有四条消息将同时写入管道的内部缓冲区。第一条消息异步到达,因此您会错过它,但其余三条消息已经在管道中,因此这些读取可以立即完成。