Объединить два буфера в одну запись на канале Win32

Я реализую формат проводки ZeroMQ по именованным каналам Win32. Формат требует добавления сообщения с указанием его размера. Мой интерфейс выглядит как send(std::vector<unsigned char>), поэтому пользователь уже выделил буфер точного размера своих данных, и я строю заголовок размера на основе vector.size().

В настоящее время я отправляю заголовок размера в автономной записи в канал. Но тогда, если последующая запись фактического содержимого сообщения не удалась, поток данных остается в плохом состоянии, когда получатель ожидает больше данных, но отправитель считает, что сообщение не удалось.

Я хотел бы объединить заголовок размера и содержимое в одну запись канала, чтобы заголовок не проходил сам по себе. Но я бы не хотел копировать содержимое vector, потому что оно может быть довольно большим. Есть ли способ объединить два буфера в один канал записи Win32?

Если нет, я всегда могу добавить что-то вроде unsigned char *getPipeBuffer(size_t size), которое выделяет дополнительное место для заголовка. Но было бы неплохо оставить интерфейс нетронутым.


person japreiss    schedule 18.12.2012    source источник


Ответы (3)


Вы рассматривали возможность использования трубы с PIPE_READMODE_MESSAGE? Таким образом, вы получаете размер сообщения бесплатно и вам не нужно включать его в само сообщение.

При записи операция записи завершается только после записи всего сообщения.

При чтении операция чтения считывает одно сообщение. Или, если сообщение не помещается в буфер канала, считывает его часть, а затем сообщает, что есть еще ожидающие данные, и что вам нужно вызвать его снова, чтобы получить остальную часть сообщения.

Нет необходимости передавать размер сообщения, потому что получатель всегда знает, когда он закончил читать одно сообщение.

Обратите внимание, что для клиентов канала необходимо изменить режим чтения канала с помощью вызова SetNamedPipeHandleState.

Подробнее здесь .

person Fiktik    schedule 18.12.2012

Моим первым ответом было бы использовать WriteFileGather, но это связано со строгими требованиями к выравниванию буферов, которые вы передаете в функцию, что может быть трудно обеспечить, и после проверки документации кажется, что это может вообще не работать с каналами, хотя я не знаю Не понимаю, почему бы и нет.

Я думаю, что две разные записи, одна для размера и одна для данных, должны быть в порядке. Вы спрашиваете, что произойдет, если вторая запись завершится неудачно и поток останется в каком-то несогласованном состоянии, когда другой конец ожидает больше данных. Но даже один запрос на запись может оставить канал в таком состоянии: WriteFile, например, может записать меньше байтов, чем запрошено, что потребует второй записи, и эта вторая запись может завершиться неудачно.

person Nik Bougalis    schedule 18.12.2012
comment
Из документации: Каждый буфер должен быть не меньше размера страницы системной памяти и должен быть выровнен по границе размера страницы системной памяти. Это определенно не сработает, потому что заголовок ZeroMQ равен либо 1, либо 9. байт. Я согласен с вашим вторым абзацем, хотя, думаю, мне нужно быть готовым к такого рода проблемам, несмотря ни на что. - person japreiss; 18.12.2012

Обратите внимание, что страница, которую вы используете в качестве справочной информации, в начале гласит: «ВНИМАНИЕ: этот текст устарел и относится к старой версии ØMQ. Он остается здесь для исторического интереса. НЕ ИСПОЛЬЗУЙТЕ ЭТО ДЛЯ ИЗУЧЕНИЯ ØMQ».

Это не формат провода 0MQ. Если вам нужен формат проводника 0MQ, его можно найти на сайте RFC по адресу http://rfc.zeromq.org/spec. :15.

person Pieter Hintjens    schedule 23.12.2012
comment
Вау, спасибо, что обратили на это мое внимание. К счастью, я использую этот протокол только для внутреннего использования, и он не должен соответствовать ZeroMQ. Но это очень хорошо знать. Вы знаете, почему они решили изменить его? - person japreiss; 26.12.2012