Transactions sur des canaux nommés
Une transaction de canal nommé est une communication client/serveur qui combine une opération d’écriture et une opération de lecture en une seule opération réseau. Une transaction ne peut être utilisée que sur un canal duplex de type message. 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 requête sur le serveur de canal nommé et lire le message de réponse du serveur. Le client de canal doit spécifier GENERIC_READ | GENERIC_WRITE accès lorsqu’il ouvre son handle de canal en appelant la fonction CreateFile . Ensuite, le client de canal définit le handle de canal en mode 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 l’intégralité du message écrit par le serveur, la fonction retourne zéro et GetLastError retourne ERROR_MORE_DATA. Le client peut lire le reste du message en appelant la fonction ReadFile, ReadFileEx ou PeekNamedPipe .
TransactNamedPipe est généralement appelé par les clients de canal, mais peut également être utilisé par un serveur de canal.
L’exemple suivant montre un client de canal utilisant TransactNamedPipe. Ce client de canal peut être utilisé avec l’un des serveurs de canal répertorié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 des fonctions CreateFile, WaitNamedPipe (si nécessaire), TransactNamedPipe et CloseHandle en un seul appel. Étant donné que le handle de canal est fermé avant le retour de la fonction, tous les octets supplémentaires dans le message sont perdus si le message est supérieur à 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;
}
Rubriques connexes