Свойство сериализованного размера сообщения protobuf-net

Мы используем protobuf-net для сериализации и десериализации сообщений в приложении, общедоступный протокол которого основан на буферах протокола Google. Библиотека превосходна и покрывает все наши требования, кроме этого: нам нужно узнать длину сериализованного сообщения в байтах, прежде чем сообщение будет действительно сериализовано.

Вопрос уже задавался полтора года назад, и, по словам Марка, единственный способ сделать это - сериализовать его в MemoryStream и после этого прочитать свойство .Length . В нашем случае это неприемлемо, потому что MemoryStream за кулисами выделяет байтовый буфер, и мы должны этого избежать.

Эта строка из того же ответа вселяет в нас надежду, что в конце концов это возможно:

Если вы проясните, каков вариант использования, я уверен, что мы сможем легко сделать его доступным (если это еще не было).

Вот наш пример использования. У нас есть сообщения размером от нескольких байтов до двух мегабайт. Приложение предварительно выделяет байтовые буферы, используемые для операций с сокетами и для сериализации / десериализации, и после завершения фазы прогрева дополнительные буферы не могут быть созданы (подсказка: avoding GC и фрагментация кучи). По сути, байтовые буферы объединены в пулы. Мы также хотим, насколько это возможно, избегать копирования байтов между буферами / потоками.

Мы придумали две возможные стратегии, и обе они требуют размера сообщения заранее:

  1. Используйте (большие) байтовые буферы фиксированного размера и сериализуйте все сообщения, которые могут поместиться в один буфер; отправить содержимое буфера с помощью Socket.Send . Мы должны знать, когда следующее сообщение не может поместиться в буфер, и прекратить сериализацию. Без размера сообщения единственный способ добиться этого - дождаться возникновения исключения во время Serialize .
  2. Используйте (маленькие) байтовые буферы переменного размера и сериализуйте каждое сообщение в один буфер; отправить содержимое буфера с помощью Socket.Send . Чтобы извлечь из пула байтовый буфер подходящего размера, нам нужно знать, сколько байтов имеет сериализованное сообщение.

Поскольку протокол уже определен (мы не можем это изменить) и требует, чтобы префикс длины сообщения был Varint32, мы не можем использовать метод SerializeWithLengthPrefix .

Можно ли добавить в поток метод, оценивающий размер сообщения без сериализации? Если это что-то, что не вписывается в текущий набор функций и дорожную карту библиотеки, но выполнимо, мы заинтересованы в расширении библиотеки сами. Мы также ищем альтернативные подходы, если они есть.

8
задан Community 23 May 2017 в 10:29
поделиться