2012-09-22 8 views
6

Sto utilizzando Named Pipe configurato per inviare dati come flusso di un singolo byte per inviare strutture di dati serializzate tra due applicazioni. I dati serializzati cambiano in dimensioni abbastanza drammatiche. Dal lato dell'invio, questo non è un problema, posso regolare il numero di byte da inviare esattamente.Named Pipes, Come sapere il numero esatto di byte da leggere sul lato di lettura. C++, Windows

Come posso impostare il buffer sul lato di ricezione (Lettura) sul numero esatto di byte da leggere? C'è un modo per sapere quanto sono grandi i dati sul lato di invio (Scrittura)?

Ho visto PeekNamedPipe, ma la funzione appare inutile per le pipe denominate byte digitate?

lpBytesLeftThisMessage [out, opzionale] Un puntatore a una variabile che riceve il numero di byte rimanenti in questo messaggio. Questo parametro sarà zero per pipe denominate di tipo byte o per pipe anonime. Questo parametro può essere NULL se nessun dato deve essere letto.

http://msdn.microsoft.com/en-us/library/windows/desktop/aa365779(v=vs.85).aspx

Come si fa a gestire una situazione del genere meglio se non è possibile determinare l'esatta dimensione del buffer necessaria?

Invio codice

string strData; 
strData = "ShortLittleString"; 

DWORD numBytesWritten = 0; 
result = WriteFile(
    pipe, // handle to our outbound pipe 
    strData.c_str(), // data to send 
    strData.length(), // length of data to send (bytes) 
    &numBytesWritten, // will store actual amount of data sent 
    NULL // not using overlapped IO 
); 

lettura di codice:

DWORD numBytesToRead0 = 0; 
DWORD numBytesToRead1 = 0; 
DWORD numBytesToRead2 = 0; 

BOOL result = PeekNamedPipe(
pipe, 
NULL, 
42, 
&numBytesToRead0, 
&numBytesToRead1, 
&numBytesToRead2 
); 

char * buffer ; 

buffer = new char[numBytesToRead2]; 

char data[1024]; //1024 is way too big and numBytesToRead2 is always 0 
DWORD _numBytesRead = 0; 

BOOL result = ReadFile(
pipe, 
data, // the data from the pipe will be put here 
1024, // number of bytes allocated 
&_numBytesRead, // this will store number of bytes actually read 
NULL // not using overlapped IO 
); 

Nel codice precedente tampone è sempre di dimensione 0 come funzione PeakNamedPipe restituisce 0 per tutti numBytesToRead variabili. C'è un modo per impostare esattamente questa dimensione del buffer? In caso contrario, qual è il modo migliore per gestire una situazione del genere? Grazie per qualsiasi aiuto!

+0

Un approccio semplice è quello di scrivere la lunghezza, poi i dati. Il ricevitore può quindi leggere prima la lunghezza e allocare il buffer. Non diversamente dal modo in cui funziona la modalità messaggio pipe. –

risposta

1

Bene, si sta utilizzando ReadFile(). La documentazione dice, tra le altre cose:

Se una named pipe viene letto in modalità messaggio e il messaggio successivo è più lungo rispetto a quanto specificato parametri nNumberOfBytesToRead, ReadFile restituisce FALSE e GetLastError restituisce ERROR_MORE_DATA. Il resto del messaggio può essere letto da una chiamata successiva alla funzione ReadFile o PeekNamedPipe.

Hai provato? Non ho mai usato una pipa come questa :-), li ho usati solo per arrivare agli handle di stdin/out di un processo figlio.

Suppongo che quanto sopra possa essere ripetuto tutte le volte che è necessario, rendendo il "resto del messaggio" una descrizione alquanto imprecisa: penso che se il "resto" non si adatta al tuo buffer, solo ottieni un altro ERROR_MORE_DATA in modo che tu sappia ottenere il resto del resto.

Oppure, se ti sto fraintendendo completamente e in realtà non stai utilizzando questa "modalità messaggio": forse stai solo leggendo le cose nel modo sbagliato. Potresti semplicemente utilizzare un buffer di dimensioni fisse per leggere i dati e aggiungerli al blocco finale, fino a quando non hai raggiunto la fine dei dati. O ottimizzalo un po 'aumentando la dimensione del buffer di dimensione "fissa" mentre vai avanti.

+0

No, non ho. Sembra un po 'un trucco, ma stai suggerendo di leggere in incrementi molto piccoli e fare il ciclo finché non avrò più un errore ERROR_MORE_DATA? :) Questo dovrebbe funzionare, ma sto cercando di evitare di accodare le dimensioni dei dati al messaggio o finire con dati irrilevanti aggiunti ai dati serializzati, in pratica qualsiasi lavoro di pulizia basato su char/string dopo aver letto il messaggio. Non c'è modo di leggere fino a quando EOF non ama leggere un file di testo? Posso inserire il mio EOF sul lato Write, forse? – Rudolf

+0

Non sto usando la modalità messaggio, sto usando la modalità byte. :) Ma penso che tu mi abbia appena dato un'idea, penso che la modalità byte debba essere usata quando si inviano caratteri a lunghezza fissa, io triterò e cambierò il sistema in una pipe in modalità messaggio e riferirò? La modalità di byte – Rudolf

+0

è specificatamente progettata per mettere on * on * te * per gestire il protocollo di messaggistica, o la sua mancanza, per il caso di utilizzo che stai implementando. In altre parole, parte dei pipe del messaggio è l'attributo della lunghezza del messaggio. nessun attributo di questo tipo esiste in modalità byte a meno che * tu * lo gestisca inviando dati che lo rappresentano. per dirla in un altro modo, la modalità messaggio è un tipo che ti consegna una scatola con un'etichetta che dice quanto tiene. la modalità byte è solo un tipo che ti lancia il prodotto. a meno che tu non sappia cosa è nella mente del "ragazzo", non ne hai abbastanza per lavorare davvero. – WhozCraig

3

Perché pensi che non sia possibile utilizzare lpTotalBytesAvail per ottenere la dimensione dei dati inviati?Funziona sempre per me in modalità byte. Se è sempre zero, forse hai fatto qualcosa di sbagliato. Suggerire inoltre di utilizzare std::vector come buffer di dati, è molto più sicuro che fare confusione con i puntatori grezzi e la dichiarazione new.

lpTotalBytesAvail [out, optional] Un puntatore a una variabile che riceve il numero totale di byte disponibili per essere letti dalla pipe. Questo parametro può essere NULL se nessun dato deve essere letto.

codice di esempio:

// Get data size available from pipe 
DWORD bytesAvail = 0; 
BOOL isOK = PeekNamedPipe(hPipe, NULL, 0, NULL, &bytesAvail, NULL); 
if(!isOK) 
{ 
    // Check GetLastError() code 
} 

// Allocate buffer and peek data from pipe 
DWORD bytesRead = 0;  
std::vector<char> buffer(bytesAvail); 
isOK = PeekNamedPipe(hPipe, &buffer[0], bytesAvail, &bytesRead, NULL, NULL); 
if(!isOK) 
{ 
    // Check GetLastError() code 
} 
+0

ltTotalBytesAvail ha funzionato benissimo per me! Ciò mi ha risparmiato un sacco di problemi e costose copie tampone per anteporre le dimensioni come suggeriva Hans Passant. –