2012-09-22 16 views
6

Używam potoków nazwanych skonfigurowanych do wysyłania danych jako strumienia jednobajtowego w celu przesyłania serializowanych struktur danych między dwiema aplikacjami. Serializowane dane zmieniają się dość dramatycznie. Po stronie wysyłającej to nie jest problem, mogę dostosować liczbę bajtów do wysłania dokładnie.Nazwane potoki, Jak poznać dokładną liczbę bajtów do odczytania po stronie czytania. C++, Windows

Jak ustawić bufor na końcu odbierającym (Reading) na dokładną liczbę bajtów do odczytania? Czy istnieje sposób, aby wiedzieć, jak duże są dane po stronie wysyłania (pisania)?

Spojrzałem na PeekNamedPipe, ale funkcja wydaje się bezużyteczna dla bajtów o nazwanych nazwanych potokach?

lpBytesLeftThisMessage [się opcjonalnie] Wskaźnik zmiennej, która odbiera liczbę pozostałych bajtów w tym komunikacie. Ten parametr będzie wynosił zero dla nazwanych potoków lub dla anonimowych potoków. Ten parametr może mieć wartość NULL, jeśli nie można odczytać danych.

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

jaki sposób można obsłużyć takiej sytuacji najlepiej, jeśli nie można określić dokładną wymaganą wielkość bufora?

Wysyłanie Kod

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 
); 

Kod Reading:

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 
); 

W powyższym kodzie buforze jest zawsze od wielkości 0 w funkcji PeakNamedPipe zwraca 0 dla wszystkich numBytesToRead zmiennych. Czy istnieje sposób na dokładne ustawienie tego rozmiaru bufora? Jeśli nie, jaki jest najlepszy sposób poradzenia sobie z taką sytuacją? Dzięki za pomoc!

+0

Prostym sposobem jest napisać długości, potem dane. Odbiornik może następnie w prosty sposób odczytać długość i przydzielić bufor. W odróżnieniu od sposobu, w jaki działa tryb wiadomości przewodowych. –

Odpowiedz

1

Używasz ReadFile(). Dokumentacja mówi między innymi:

Jeśli nazwany potok jest odczytywany w trybie komunikatów i następny komunikat jest dłuższy niż Parametr nNumberOfBytesToRead, ReadFile zwróci FALSE i GetLastError zwraca ERROR_MORE_DATA. Pozostałą część wiadomości można odczytać przez kolejne wywołanie ReadFile lub PeekNamedPipefunction.

Próbowałeś tego? Nigdy nie używałem takiej fajki :-), używano ich tylko do przechodzenia do uchwytów stdin/out procesu potomnego.

Zakładam, że powyższe może być powtarzane tak często, jak to konieczne, co czyni "pozostałą część wiadomości" nieco niedokładnym opisem: myślę, że jeśli "pozostała część" nie mieści się w twoim buforze, po prostu zdobądź kolejną ERROR_MORE_DATA, dzięki czemu otrzymasz pozostałą część reszty.

Albo, jeśli całkowicie cię nie rozumiem, a właściwie nie używasz tego "trybu wiadomości": może po prostu czytasz rzeczy w niewłaściwy sposób. Możesz po prostu użyć bufora o stałym rozmiarze, aby odczytać dane i dołączyć je do ostatniego bloku, dopóki nie dotrzesz do końca danych. Lub zoptymalizuj to nieco, zwiększając rozmiar "ustalonego" bufora rozmiaru, kiedy jedziesz.

+0

Nie, nie mam. Wydaje się, że to trochę hack, ale czy sugerujesz, że czytam w bardzo małych przyrostach i pętlę, dopóki nie otrzymam błędu ERROR_MORE_DATA? :) To powinno zadziałać, ale staram się unikać dołączania rozmiaru danych do wiadomości lub kończenia z nieistotnymi danymi dołączonymi do zserializowanych danych - zasadniczo wszelkie prace czyszczące oparte na łańcuchach znaków/ciągach po przeczytaniu wiadomości. Czy nie ma sposobu, aby przeczytać EOF jak czytanie pliku tekstowego? Czy mogę wstawić własny EOF po stronie Write? – Rudolf

+0

Nie używam trybu wiadomości, używam trybu bajtowego. :) Ale myślę, że właśnie wpadłeś na pomysł, myślę, że tryb bajtowy ma być używany podczas wysyłania ustalonej długości znaków, będę ciąć i zmieniać system na rurkę trybu wiadomości i zgłaszać z powrotem? – Rudolf

+0

Tryb bajtowy został specjalnie zaprojektowany, aby wprowadzić użytkownika * ciebie * w celu zarządzania protokołem przesyłania wiadomości lub jego brakiem w przypadku wykorzystywanego przypadku użycia. Innymi słowy, częścią message-pipes jest atrybut długości komunikatu. nie ma takiego atrybutu w trybie bajtowym, chyba że * Ty * zarządzasz nim, przesyłając dane, które go reprezentują. Mówiąc inaczej, trybem wiadomości jest facet podający ci pudełko, które ma na sobie etykietkę mówiącą, ile ona trzyma. tryb bajtowy to po prostu facet rzucający w ciebie produktem. chyba że wiesz, co jest w umyśle "faceta", z którym nie masz dość pracy. – WhozCraig

3

Dlaczego według Ciebie nie można użyć numeru lpTotalBytesAvail, aby uzyskać rozmiar wysłanej wiadomości?Zawsze działa dla mnie w trybie bajtów. Jeśli zawsze jest zero, prawdopodobnie zrobiłeś coś złego. Sugerujemy również użycie std::vector jako bufora danych, jest to o wiele bezpieczniejsze niż mieszanie z surowymi wskaźnikami i instrukcją new.

lpTotalBytesAvail [out, optional] Wskaźnik do zmiennej, która odbiera całkowitą liczbę bajtów do odczytania z potoku. Ten parametr może mieć wartość NULL, jeśli nie można odczytać danych.

Przykładowy kod:

// 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

lpTotalBytesAvail działało świetnie dla mnie! To zaoszczędziło mi wiele kłopotów i drogich kopii bufora, aby zwiększyć rozmiar, jak zasugerował Hans Passant. –

Powiązane problemy