Transazioni su Named Pipe
Una transazione denominata pipe è una comunicazione client/server che combina un'operazione di scrittura e un'operazione di lettura in una singola operazione di rete. Una transazione può essere usata solo in una pipe di tipo messaggio duplex. Le transazioni migliorano le prestazioni delle comunicazioni di rete tra un client e un server remoto. I processi possono usare le funzioni TransactNamedPipe e CallNamedPipe per eseguire transazioni pipe denominate.
La funzione TransactNamedPipe è più comunemente usata da un client di pipe per scrivere un messaggio di richiesta al server pipe denominato e leggere il messaggio di risposta del server. Il client della pipe deve specificare GENERIC_READ | GENERIC_WRITE l'accesso quando apre il relativo handle pipe chiamando la funzione CreateFile . Il client pipe imposta quindi l'handle della pipe in modalità di lettura messaggio chiamando la funzione SetNamedPipeHandleState . Se il buffer di lettura specificato nella chiamata a TransactNamedPipe non è sufficiente per contenere l'intero messaggio scritto dal server, la funzione restituisce zero e GetLastError restituisce ERROR_MORE_DATA. Il client può leggere il resto del messaggio chiamando la funzione ReadFile, ReadFileEx o PeekNamedPipe.
TransactNamedPipe viene in genere chiamato dai client pipe, ma può anche essere usato da un server di pipe.
Nell'esempio seguente viene illustrato un client di pipe usando TransactNamedPipe. Questo client di pipe può essere usato con uno qualsiasi dei server di pipe elencati in Vedere anche.
#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 di pipe usa CallNamedPipe per combinare la funzione CreateFile, WaitNamedPipe (se necessario), TransactNamedPipe e CloseHandle chiama in una singola chiamata. Poiché l'handle della pipe viene chiuso prima che la funzione restituisca, eventuali byte aggiuntivi nel messaggio vengono persi se il messaggio è maggiore della dimensione specificata del buffer di lettura. L'esempio seguente è l'esempio precedente riscritto per l'uso di 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;
}
Argomenti correlati