Transactions sur les canaux nommés

Une transaction de canal nommé est une communication client/serveur qui associe une opération d’écriture et une opération de lecture dans une opération de réseau unique. Une transaction ne peut être utilisée que sur un canal de type de message duplex. Les transactions améliorent les performances des communications réseau entre un client et un serveur distant. Les processus peuvent utiliser les fonctions TransactNamedPipe et CallNamedPipe pour effectuer des transactions de canal nommé.

La fonction TransactNamedPipe est généralement utilisée par un client de canal pour écrire un message de demande au serveur de canaux nommés et lire le message de réponse du serveur. Le client de canal doit spécifier _ | _ un accès en écriture générique de lecture générique lorsqu’il ouvre son handle de canal en appelant la fonction CreateFile . Ensuite, le client de canal définit le descripteur de canal en mode de lecture de message en appelant la fonction SetNamedPipeHandleState . Si la mémoire tampon de lecture spécifiée dans l’appel à TransactNamedPipe n’est pas assez grande pour contenir le message entier écrit par le serveur, la fonction retourne zéro et GETLASTERROR retourne l’erreur _ plus de _ données. Le client peut lire le reste du message en appelant la fonction ReadFile, ReadFileExou PeekNamedPipe .

TransactNamedPipe est généralement appelé par les clients de canal, mais peut également être utilisé par un serveur de canaux.

L’exemple suivant montre un client de canal à l’aide de TransactNamedPipe. Ce client de canal peut être utilisé avec l’un des serveurs de canaux listés sous Voir aussi.

#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 client de canal utilise CallNamedPipe pour combiner les appels de fonction CreateFile, WaitNamedPipe (si nécessaire), TransactNamedPipeet CloseHandle dans un appel unique. Étant donné que le descripteur de canal est fermé avant le retour de la fonction, tout octet supplémentaire dans le message est perdu si le message est plus grand que la taille spécifiée de la mémoire tampon de lecture. L’exemple suivant est l’exemple précédent réécrit pour utiliser 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; 
}

Serveur de canaux multithread

Serveur de canaux nommés utilisant des e/s avec chevauchement

Serveur de canaux nommés utilisant les routines de saisie semi-automatique