2011-12-16 10 views
5

He escrito una clase para manejar conexiones de canalización con nombre, y si creo una instancia, la cierro y luego intento crear otra instancia. Devuelve la llamada al CreateFile(). INVALID_HANDLE_VALUE y GetLastError() devuelve ERROR_PIPE_BUSY. ¿Que está pasando aqui? ¿Qué puedo hacer para asegurar que la llamada al Connect() sea exitosa?Pipe con nombre CreateFile() devuelve INVALID_HANDLE_VALUE, y GetLastError() devuelve 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(); 

Éstos son mis implementaciones de Connect() y 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: olvidé de decirle cómo llegué a la conclusión de este ... me puse romper puntos indicados en los comentarios Cuando se ejecuta, se detiene en el primer punto de ruptura.

EDIT: Este es mi código actualizado

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 /* 

Ahora, WaitNamedPipe() está volviendo falsa en la segunda llamada a Connect() y GetLastError() está regresando 2, o ERROR_FILE_NOT_FOUND?

+1

Un consejo: '\\', '\ p' y' \ t' se interpretarán como caracteres de escape. Cambie a barras diagonales inversas o barras diagonales inversas dobles para "escapar de los escapes": '" \\\\. \\ pipe \\ test "'. – Xeo

+0

Eso fue un error ... Lo corrigí ... –

Respuesta

2

De Named Pipe Client:

Si existe la tubería, pero todas sus instancias están ocupados, CreateFile vuelve INVALID_HANDLE_VALUE y la función GetLastError devuelve ERROR_PIPE_BUSY. Cuando esto sucede, el cliente de canalización con nombre utiliza la función WaitNamedPipe para esperar a que una instancia de la canalización con nombre a esté disponible.

El enlace tiene código de ejemplo para hacer frente a ERROR_PIPE_BUSY.

EDIT:

pequeño ejemplo compilables que demuestra la aceptación y la conexión de una tubería con nombre:

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

Ejecutar del lado del servidor en primer lugar:

pipetest.exe server 

luego ejecutar en el cliente:

pipetest.exe client 

No pude decir cuál era el problema del código publicado. Espero que este pequeño ejemplo lo ayude a encontrar el problema.

+0

Cambié mi código para seguir esa lógica, y ahora 'WaitNamedPipe()' devuelve falso, y GetLastError() está devolviendo 'ERROR_FILE_NOT_FOUND' –

+0

También probé la lógica de bucle en el ejemplo de MSDN, y obtengo el mismo resultado.'CreateFile()' devuelve 'INVALID_HANDLE_VALUE', luego' GetLastError() 'devuelve' ERROR_PIPE_BUSY', 'WaitNamedPipe()' devuelve 'FALSE', y' GetLastError() 'devuelve' ERROR_FILE_NOT_FOUND'. –

+0

¿Crea un conducto con nombre llamado "\\\\. \\ pipe \\ test"? Se está creando un conducto con nombre utilizando [CreateNamedPipe()] (http://msdn.microsoft.com/en-us/library/windows/desktop/aa365150%28v=vs.85%29.aspx). – hmjd

Cuestiones relacionadas