Частичная десериализация с протобуфом

Марк или любой, кто имеет опыт работы с protobuf-net:

У меня есть архитектура, где сервер поддерживает постоянные соединения с клиентами в течение всей жизни (через TCP). Поскольку уровень соединения / сервер должен иметь высокое время безотказной работы, он только десериализует сообщения и передает их на сервер приложений / уровень. Сама логика бизнеса не содержит.

 clients -> connection layer (deserialization) -> app layer (business logic)

Проблема заключается в том, что, хотя теперь я могу вносить изменения в логику бизнеса, я НЕ могу изменить модель, совместно используемую уровнем приложений и клиентами, поскольку уровень соединений зависит от модели десериализации.

Есть ли способ, чтобы уровень соединения только ЧАСТИЧНО десериализировал сообщения в базовый класс для целей пересылки / маршрутизации?

В противном случае, я думаю, мне придется создать двоичное поле в базовом классе, которое передается как есть и десериализуется уровнем приложения. Одна стадия сериализации, две стадии десериализации.

РЕДАКТИРОВАТЬ: выделено

class Message
{
  User user;
  // not much else in here, potentially routing information
}

class RequestType1: Message
{
 // lots of fields 
 // which are specific to this type of request/reply 
}

class RequestType2: Message
{

}

Уровень соединения не должен заботиться о структуре конкретных типов запросов. Таким образом, я могу изменить их по своему усмотрению, если и клиентский уровень, и уровень приложения согласны. Но в настоящее время уровень соединения выполняет десериализацию, поэтому ему НЕОБХОДИМО знать модель, и любые изменения вынуждают меня перезапускать сервер соединений.

Мне просто нужно его десериализовать достаточно для маршрутизации, что означает "информация о пользователе" + "имя / номер подтипа".

1 ответ

Решение

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

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

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

Пример заголовка запроса:

  • версия заголовка (byte)
  • Тип содержимого (byte) (вам нужно где-то создать отображение)
  • длина контента (int)

В настоящее время я пишу небольшой аддон для моего Griffin.Networking ( http://github.com/jgauffin/griffin.networking), который будет иметь небольшой заголовок и использовать protobuf для сообщений. Смотреть проект, чтобы получить обновление, когда он будет зафиксирован.

Другие вопросы по тегам