简体   繁体   English

未收到C ++ Windows Asynch IO命名管道优先消息

[英]C++ Windows Asynch IO Named Pipe first message not received

Modified code from Named Pipe Server Using Overlapped I/O https://msdn.microsoft.com/en-us/library/windows/desktop/aa365603(v=vs.85).aspx 使用重叠I / O从命名管道服务器修改的代码https://msdn.microsoft.com/zh-cn/library/windows/desktop/aa365603(v=vs.85).aspx

The server code is as follows: 服务器代码如下:

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

The client code is as follows: 客户端代码如下:

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

} }

The server never receives message A but B, C, D are received OK. 服务器从不接收消息A,但可以接收到B,C,D。 If you uncomment //Sleep(1000) in the client, only B and D are received. 如果在客户端中取消注释// Sleep(1000),则仅接收到B和D。

Any idea as to why this happens? 知道为什么会这样吗? The server output with out the sleep is as follows: 不休眠的服务器输出如下:

 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

In the server's read loop, you are discarding any data that arrives asynchronously. 在服务器的读取循环中,您将丢弃异步到达的所有数据。

After GetOverlappedResult() has reported that the pending I/O operation is complete, the buffer contains the data from that operation. GetOverlappedResult()报告完成挂起的I / O操作后,缓冲区将包含该操作中的数据。 You're ignoring that data and issuing a new read operation into the same buffer. 您将忽略该数据,并向同一缓冲区发出新的读取操作。

The only reason you get any of the messages is that (on most runs) all four messages will be written into the pipe's internal buffer at the same time. 收到任何一条消息的唯一原因是(在大多数运行中)所有这四个消息将同时写入管道的内部缓冲区。 The first message arrives asynchronously, so you miss it, but the remaining three messages are already in the pipe so those reads can complete immediately. 第一条消息异步到达,因此您会错过它,但是其余三条消息已经在管道中,因此这些读取可以立即完成。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM