Compartir a través de


Transacciones en canalizaciones con nombre

Una transacción de canalización con nombre es una comunicación de cliente/servidor que combina una operación de escritura y una operación de lectura en una sola operación de red. Una transacción solo se puede usar en una canalización de tipo de mensaje dúplex. Las transacciones mejoran el rendimiento de las comunicaciones de red entre un cliente y un servidor remoto. Los procesos pueden usar las funciones TransactNamedPipe y CallNamedPipe para realizar transacciones de canalización con nombre.

La función TransactNamedPipe se usa normalmente por un cliente de canalización para escribir un mensaje de solicitud en el servidor de canalización con nombre y leer el mensaje de respuesta del servidor. El cliente de canalización debe especificar GENERIC_READ | GENERIC_WRITE acceso cuando abre su identificador de canalización mediante una llamada a la función CreateFile . A continuación, el cliente de canalización establece el identificador de canalización en modo de lectura de mensajes llamando a la función SetNamedPipeHandleState . Si el búfer de lectura especificado en la llamada a TransactNamedPipe no es lo suficientemente grande como para contener todo el mensaje escrito por el servidor, la función devuelve cero y GetLastError devuelve ERROR_MORE_DATA. El cliente puede leer el resto del mensaje llamando a la función ReadFile, ReadFileEx o PeekNamedPipe.

Los clientes de canalización suelen llamar a TransactNamedPipe, pero también los puede usar un servidor de canalización.

En el ejemplo siguiente se muestra un cliente de canalización mediante TransactNamedPipe. Este cliente de canalización se puede usar con cualquiera de los servidores de canalización enumerados en Ver también.

#include <windows.h> 
#include <stdio.h>
#include <conio.h>
#include <tchar.h>

#define BUFSIZE 512
 
int _tmain(int argc, TCHAR *argv[]) 
{ 
   HANDLE hPipe; 
   LPTSTR lpszWrite = TEXT("Default message from client"); 
   TCHAR chReadBuf[BUFSIZE]; 
   BOOL fSuccess; 
   DWORD cbRead, dwMode; 
   LPTSTR lpszPipename = TEXT("\\\\.\\pipe\\mynamedpipe"); 

   if( argc > 1)
   {
      lpszWrite = argv[1]; 
   }
 
   // Try to open a named pipe; wait for it, if necessary. 
    while (1) 
   { 
      hPipe = CreateFile( 
         lpszPipename,   // pipe name 
         GENERIC_READ |  // read and write access 
         GENERIC_WRITE, 
         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\n"); 
         return 0;
      }
 
      // All pipe instances are busy, so wait for 20 seconds. 
      if (! WaitNamedPipe(lpszPipename, 20000) ) 
      {
         printf("Could not open pipe\n"); 
         return 0;
      }
  } 
 
   // The pipe connected; change to message-read mode. 
   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) 
   {
      printf("SetNamedPipeHandleState failed.\n"); 
      return 0;
   }
 
   // Send a message to the pipe server and read the response. 
   fSuccess = TransactNamedPipe( 
      hPipe,                  // pipe handle 
      lpszWrite,              // message to server
      (lstrlen(lpszWrite)+1)*sizeof(TCHAR), // message length 
      chReadBuf,              // buffer to receive reply
      BUFSIZE*sizeof(TCHAR),  // size of read buffer
      &cbRead,                // bytes read
      NULL);                  // not overlapped 

   if (!fSuccess && (GetLastError() != ERROR_MORE_DATA)) 
   {
      printf("TransactNamedPipe failed.\n"); 
      return 0;
   }
 
   while(1)
   { 
      _tprintf(TEXT("%s\n"), chReadBuf);

      // Break if TransactNamedPipe or ReadFile is successful
      if(fSuccess)
         break;

      // Read from the pipe if there is more data in the message.
      fSuccess = ReadFile( 
         hPipe,      // pipe handle 
         chReadBuf,  // buffer to receive reply 
         BUFSIZE*sizeof(TCHAR),  // size of buffer 
         &cbRead,  // number of bytes read 
         NULL);    // not overlapped 

      // Exit if an error other than ERROR_MORE_DATA occurs.
      if( !fSuccess && (GetLastError() != ERROR_MORE_DATA)) 
         break;
      else _tprintf( TEXT("%s\n"), chReadBuf); 
   }

   _getch(); 

   CloseHandle(hPipe); 
 
   return 0; 
}

Un cliente de canalización usa CallNamedPipe para combinar las llamadas a la función CreateFile, WaitNamedPipe (si es necesario), TransactNamedPipe y CloseHandle en una sola llamada. Dado que el identificador de canalización se cierra antes de que la función devuelva, se pierden los bytes adicionales del mensaje si el mensaje es mayor que el tamaño especificado del búfer de lectura. El ejemplo siguiente es el ejemplo anterior reescrito para usar CallNamedPipe.

#include <windows.h> 
#include <stdio.h>
#include <conio.h>
#include <tchar.h>

#define BUFSIZE 512
 
int _tmain(int argc, TCHAR *argv[]) 
{ 
   LPTSTR lpszWrite = TEXT("Default message from client"); 
   TCHAR chReadBuf[BUFSIZE]; 
   BOOL fSuccess; 
   DWORD cbRead; 
   LPTSTR lpszPipename = TEXT("\\\\.\\pipe\\mynamedpipe"); 

   if( argc > 1)
   {
      lpszWrite = argv[1]; 
   }
 
   fSuccess = CallNamedPipe( 
      lpszPipename,        // pipe name 
      lpszWrite,           // message to server 
      (lstrlen(lpszWrite)+1)*sizeof(TCHAR), // message length 
      chReadBuf,              // buffer to receive reply 
      BUFSIZE*sizeof(TCHAR),  // size of read buffer 
      &cbRead,                // number of bytes read 
      20000);                 // waits for 20 seconds 
 
   if (fSuccess || GetLastError() == ERROR_MORE_DATA) 
   { 
      _tprintf( TEXT("%s\n"), chReadBuf ); 
    
      // The pipe is closed; no more data can be read. 
 
      if (! fSuccess) 
      {
         printf("\nExtra data in message was lost\n"); 
      }
   }
 
   _getch(); 

   return 0; 
}

Servidor de canalización multiproceso

Servidor de canalización con nombre mediante E/S superpuesta

Servidor de canalización con nombre mediante rutinas de finalización