Я использую именованные каналы, настроенные на отправку данных в виде одного байтового потока для отправки сериализованных структур данных между двумя приложениями. Сериализованные данные изменяются в размерах довольно резко. На отправляющей стороне это не проблема, я могу точно настроить количество байтов для отправки.
Как установить в буфере на принимающем конце (чтение) точное количество байтов для чтения? Есть ли способ узнать, насколько велики данные на стороне отправки (записи)?
Я посмотрел на PeekNamedPipe, но функция кажется бесполезной для байтовых именованных каналов?
lpBytesLeftThisMessage [out, необязательно] Указатель на переменную, которая получает количество байтов, оставшихся в этом сообщении. Этот параметр будет нулевым для именованных каналов байтового типа или для анонимных каналов. Этот параметр может быть НЕДЕЙСТВИТЕЛЕН, если никакие данные не должны быть прочитаны.
http://msdn.microsoft.com/en-us/library/windows/desktop/aa365779(v=vs.85).aspx
Как лучше всего справиться с такой ситуацией, если вы не можете определить точный требуемый размер буфера?
Код отправки
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
);
Чтение кода:
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
);
В коде выше буфер всегда имеет размер 0, так как функция PeakNamedPipe возвращает 0 для всех numBytesToRead переменные. Есть ли способ установить этот размер буфера точно? Если нет, то как лучше всего справиться с такой ситуацией? Спасибо за любую помощь!
Почему вы думаете, что не могли использовать lpTotalBytesAvail
получить размер отправленных данных? У меня всегда работает в байтовом режиме. Если это всегда ноль, возможно, вы сделали что-то не так. Также предлагаем использовать std::vector
в качестве буфера данных, это гораздо более безопасно, чем возиться с необработанными указателями и new
заявление.
lpTotalBytesAvail [out, optional]
Указатель на переменную, которая получает общее количество байтов, доступных для чтения из канала. Этот параметр может быть НЕДЕЙСТВИТЕЛЕН, если никакие данные не должны быть прочитаны.
Образец кода:
// 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
}
Ну, вы используете ReadFile (). Документация говорит, среди прочего:
Если именованный канал читается в режиме сообщений, а следующее сообщение длиннее
чем параметр nNumberOfBytesToRead указывает, ReadFile возвращает FALSE и
GetLastError возвращает ERROR_MORE_DATA. Остальную часть сообщения можно прочитать
последующим вызовом функции ReadFile или PeekNamedPipe.
Ты пробовал это? Я никогда не использовал такой канал :-), только использовал их, чтобы добраться до дескрипторов stdin / out дочернего процесса.
Я предполагаю, что вышеупомянутое можно повторять так часто, как это необходимо, что делает «остаток сообщения» несколько неточным описанием: я думаю, что если «остаток» не помещается в ваш буфер, вы просто получите еще одну ERROR_MORE_DATA, так что Вы знаете, чтобы получить остаток от остатка.
Или, если я полностью вас неправильно понимаю, а вы на самом деле не используете эту вещь в «режиме сообщений»: возможно, вы просто читаете вещи неправильно. Вы можете просто использовать буфер фиксированного размера для чтения данных и добавления их в свой последний блок, пока не достигнете конца данных. Или немного оптимизируйте это, увеличивая размер буфера фиксированного размера по мере продвижения.