2011-08-05 17 views
6

Tengo un servidor y un cliente de pipa nombrados. (Haciendo esto en VC++).Problema al volver a conectar a la tubería con nombre

servidor hace

  1. CreateNamedPipe
  2. ConnectNamedPipe
  3. WriteFile
  4. Desconectar
  5. Repetir desde 2 a 4

Clie nt hace

  1. CreateFile
  2. ReadFile

El orden de ejecución es el siguiente,

  1. Servidor - CreateNamedPipe
  2. Client - CreateFile
  3. Servidor - - ConnectNamedPipe (debe regresar inmediatamente como cl ient ya está conectado)
  4. Servidor - escritura de archivo
  5. Cliente - ReadFile
  6. Servidor - DisconnectNamedPipe
  7. Cliente - CloseHandle
  8. Goto 2

Esto funciona muy bien para la primera hora. Sin embargo, el problema ocurre cuando el cliente intenta conectarse por segunda vez. Cuando el cliente intenta conectarse (CreateFile) por segunda vez antes de el servidor hizo ConnectNamedPipe (pero después de disconnectnamedpipe), obtiene ERROR_PIPE_BUSY. Funciona si el cliente llama a createfile después de que el servidor llame a ConnectNamedPipe.

¿Hay alguna forma de que pueda conectarme al cliente (CreateFile) antes del servidor llamado ConnectNamedPipe (después de DisconnectNamedPipe)?

código del servidor:

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

Código Cliente:

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

Respuesta

8

Si obtiene ERROR_PIPE_BUSY en la llamada CreateFile() en el cliente, es necesario llamar WaitNamedPipe() y vuelva a intentar cuando devoluciones. Si obtiene un retorno de cero de WaitNamedPipe(), significa que se agotó el tiempo de espera sin que la tubería esté disponible. Nunca verás que eso ocurra si pasas NMPWAIT_WAIT_FOREVER como tiempo de espera.

También debe tener en cuenta que la tubería puede volver a estar ocupada entre el momento en que WaitNamedPipe() regrese y llame a CreateFile(); por lo tanto, debe hacerlo en un bucle.De esta manera:

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 
} 

EDIT:

que simplifica el código y ahora funciona bien. El servidor de trabajo y el cliente siguen.

Servidor:

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

Cliente:

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

Gracias por la respuesta. Intenté con este código, pero el cliente sigue recibiendo ERROR_PIPE_BUSY. Una vez que el servidor llama a ConnectNamedPipe(), el cliente puede crear CreateFile() sin ningún error. – Ashwin

+0

Se actualizó la pregunta sobre el código de servidor y cliente – Ashwin

+0

@Ashwin: ver las ediciones para responder. –

-2

En el lado del servidor cuando se decida a romper la conexión que debe utilizar la cadena:

1) CloseHandle (Pipe);

2) DisconnectNamedPipe (Pipe);

Cuestiones relacionadas