2011-12-16 24 views
5

Ho scritto una classe per gestire le connessioni named pipe, e se creo un'istanza, la chiudo e quindi provo a creare un'altra istanza la chiamata a CreateFile() restituisce INVALID_HANDLE_VALUE e GetLastError() restituisce ERROR_PIPE_BUSY. Cosa sta succedendo qui? Cosa posso fare per assicurarsi che la chiamata a Connect() abbia successo?Named Pipe CreateFile() restituisce INVALID_HANDLE_VALUE e GetLastError() restituisce ERROR_PIPE_BUSY

PipeAsync A, B; 

A.Connect("\\\\.\\pipe\\test",5000); 
A.Close(); 

cout << GetLastError(); // some random value 
B.Connect("\\\\.\\pipe\\test",5000); 
cout << GetLastError(); // 231 (ERROR_PIPE_BUSY) 
B.Close(); 

Qui sono i miei implementazioni di Connect() e Close()

BOOL PipeAsync::Connect(LPCSTR pszPipeName, DWORD dwTimeout) 
{ 
    this->pszPipeName = pszPipeName; 
    this->fExisting = TRUE; 
    DWORD dwMode = this->fMessageMode ? PIPE_READMODE_MESSAGE : PIPE_READMODE_BYTE; 

    hPipe = CreateFile(
     this->pszPipeName, 
     GENERIC_READ | GENERIC_WRITE, 
     0, 
     NULL, 
     OPEN_EXISTING, 
     FILE_FLAG_OVERLAPPED, 
     NULL); 

    if(INVALID_HANDLE_VALUE == hPipe) 
     return FALSE; /* set break point here ; breaks here on second call to Connect() */ 

    if(GetLastError() == ERROR_PIPE_BUSY) 
     if(!WaitNamedPipe(this->pszPipeName, dwTimeout)) 
      return FALSE; /* set break point here */ 

    if(!SetNamedPipeHandleState(hPipe, &dwMode, NULL, NULL)) 
     return FALSE; /* set break point here */ 

    return TRUE; 

} 

VOID PipeAsync::Close() 
{ 

    if(fExisting) 
     DisconnectNamedPipe(hPipe); 

    CloseHandle(hPipe); 
} 



EDIT: Ho dimenticato di dirvi come ho concluso questo ... ho impostato rompere punti indicati nei commenti. Quando è in esecuzione, si ferma sul primo punto di interruzione.

EDIT: Questo è il mio codice aggiornato

if(INVALID_HANDLE_VALUE == hPipe) 
    if(GetLastError() == ERROR_PIPE_BUSY) 
    { 
     if(!WaitNamedPipe(this->pszPipeName, dwTimeout)) 
      return FALSE; /* break-point: breaks here on second call */ 
    } 
    else 
     return FALSE; /* break-point /* 

Ora, WaitNamedPipe() sta tornando falso in seconda convocazione per Connect() e GetLastError() sta tornando 2, o ERROR_FILE_NOT_FOUND?

+1

Un consiglio: '\\', '\ p' e' \ t' verranno interpretati come caratteri di escape. Passa alle barre di avanzamento o al doppio backslash per "sfuggire agli escape": '" \\\\. \\ pipe \\ test "'. – Xeo

+0

Quello era un refuso ... L'ho corretto ... –

risposta

2

Da Named Pipe Client:

Se il tubo esiste ma tutte le relative istanze sono impegnati, CreateFile rendimenti INVALID_HANDLE_VALUE e la funzione GetLastError restituisce ERROR_PIPE_BUSY. In questo caso, il client named pipe utilizza la funzione WaitNamedPipe per attendere che un'istanza della named pipe a diventi disponibile.

Il collegamento ha un codice di esempio su come affrontare ERROR_PIPE_BUSY.

EDIT:

piccolo esempio compilabile che illustra l'accettazione e il collegamento su un tubo di nome:

const char* const PIPE_NAME = "\\\\.\\pipe\\test"; 
const int MAX_CONNECTIONS = 10; 

void client_main() 
{ 
    DWORD last_error; 
    unsigned int elapsed_seconds  = 0; 
    const unsigned int timeout_seconds = 5; 

    HANDLE handle = CreateFile(PIPE_NAME, 
           GENERIC_READ | GENERIC_WRITE, 
           0, 
           0, 
           OPEN_EXISTING, 
           FILE_ATTRIBUTE_NORMAL, 
           0); 

    while (INVALID_HANDLE_VALUE == handle && 
      elapsed_seconds < timeout_seconds) 
    { 
     last_error = GetLastError(); 

     if (last_error != ERROR_PIPE_BUSY) 
     { 
      break; 
     } 

     Sleep(1 * 1000); 
     elapsed_seconds++; 

     handle = CreateFile(PIPE_NAME, 
          GENERIC_READ | GENERIC_WRITE, 
          0, 
          0, 
          OPEN_EXISTING, 
          FILE_ATTRIBUTE_NORMAL, 
          0); 
    } 

    if (INVALID_HANDLE_VALUE == handle) 
    { 
     std::cerr << "Failed to connect to pipe " << PIPE_NAME << 
      ": last_error=" << last_error << "\n"; 
    } 
    else 
    { 
     std::cout << "Connected to pipe " << PIPE_NAME << "\n"; 
     CloseHandle(handle); 
    } 
} 

HANDLE _get_server_handle() 
{ 
    // Error handling omitted for security descriptor creation. 
    SECURITY_DESCRIPTOR sd; 
    InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION); 
    SetSecurityDescriptorDacl(&sd, TRUE, static_cast<PACL>(0), FALSE); 

    SECURITY_ATTRIBUTES sa; 
    sa.nLength    = sizeof(sa); 
    sa.lpSecurityDescriptor = &sd; 
    sa.bInheritHandle  = FALSE; 

    // Create a bi-directional message pipe. 
    HANDLE handle = CreateNamedPipe(PIPE_NAME, 
            PIPE_ACCESS_DUPLEX, 
            PIPE_TYPE_MESSAGE  | 
             PIPE_READMODE_MESSAGE | 
             PIPE_NOWAIT, 
            PIPE_UNLIMITED_INSTANCES, 
            4096, 
            4096, 
            0, 
            &sa); 

    if (INVALID_HANDLE_VALUE == handle) 
    { 
     std::cerr << "Failed to create named pipe handle: last_error=" << 
      GetLastError() << "\n"; 
    } 

    return handle; 
} 

void server_main() 
{ 
    HANDLE handle = _get_server_handle(); 

    if (INVALID_HANDLE_VALUE != handle) 
    { 
     int count = 0; 
     while (count < MAX_CONNECTIONS) 
     { 
      BOOL result = ConnectNamedPipe(handle, 0); 

      const DWORD last_error = GetLastError(); 

      if (ERROR_NO_DATA == last_error) 
      { 
       count++; 
       std::cout << "A client connected and disconnected: count=" << 
        count << "\n"; 
       CloseHandle(handle); 
       handle = _get_server_handle(); 
      } 
      else if (ERROR_PIPE_CONNECTED == last_error) 
      { 
       count++; 
       std::cout << "A client connected before call to " << 
        "ConnectNamedPipe(): count=" << count << "\n"; 
       CloseHandle(handle); 
       handle = _get_server_handle(); 
      } 
      else if (ERROR_PIPE_LISTENING != last_error) 
      { 
       std::cerr << "Failed to wait for connection: last_error=" << 
        GetLastError() << "\n"; 
       CloseHandle(handle); 
       break; 
      } 
      Sleep(100); 
     } 
    } 
} 

int main(int a_argc, char** a_argv) 
{ 
    if (2 == a_argc) 
    { 
     if (std::string("client") == *(a_argv + 1)) 
     { 
      for (int i = 0; i < MAX_CONNECTIONS; i++) 
      { 
       client_main(); 
      } 
     } 
     else if (std::string("server") == *(a_argv + 1)) 
     { 
      server_main(); 
     } 
    } 
    return 0; 
} 

Eseguire sul lato server prima:

pipetest.exe server 

quindi eseguire sul lato client:

pipetest.exe client 

Non riuscivo a capire quale fosse il problema dal codice pubblicato. Speriamo che questo piccolo esempio ti assista nel trovare il problema.

+0

Ho cambiato il mio codice per seguire quella logica, e ora 'WaitNamedPipe()' restituisce false, e GetLastError() restituisce 'ERROR_FILE_NOT_FOUND' –

+0

Ho anche provato la logica di loop nell'esempio MSDN e ottengo lo stesso risultato.'CreateFile()' restituisce 'INVALID_HANDLE_VALUE', quindi' GetLastError() 'restituisce' ERROR_PIPE_BUSY', 'WaitNamedPipe()' restituisce 'FALSE', e' GetLastError() 'restituisce' ERROR_FILE_NOT_FOUND'. –

+0

Si crea una named pipe chiamata "\\\\. \\ pipe \\ test"? Una pipe denominata viene creata utilizzando [CreateNamedPipe()] (http://msdn.microsoft.com/en-us/library/windows/desktop/aa365150%28v=vs.85%29.aspx). – hmjd

Problemi correlati