Буферы протокола обнаруживают тип из необработанного сообщения

Можно ли определить тип сообщения буфера необработанного протокола (в байте [])

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

Я использую protobuf-net

Ответ 1

Вы не можете определить тип в изоляции, поскольку спецификация protobuf не добавляет никаких данных в поток для этого; однако есть несколько способов сделать это легко, в зависимости от контекста:

  • тип объединения (как упоминал Джон) охватывает ряд сценариев
  • inheritance (protobuf-net specific) может быть универсальным - вы можете иметь тип базового сообщения и любое количество конкретных типов сообщений
  • вы можете использовать префикс для указания входящего типа

последний подход действительно очень ценен в случае необработанных потоков TCP; это на проводе, идентичном типу объединения, но с другой реализацией; заранее определив, что 1 = Foo, 2 = Bar и т.д. (как и для подхода типа объединения), вы можете использовать SerializeWithLengthPrefix для записи (с указанием номера 1/2/etc в качестве номера поля) -generic TryDeserializeWithLengthPrefix (это находится в разделе Serializer.NonGeneric в API v1 или в TypeModel в API v2), вы можете предоставить карту типов, которая решает числа обратно к типам и, следовательно, десериализует правильный тип, И чтобы упредить вопрос "почему это полезно в потоках TCP?" - потому что: в текущем потоке TCP вам нужно использовать методы WithLengthPrefix в любом случае, чтобы избежать чрезмерного чтения потока; поэтому вы можете получить идентификатор типа бесплатно!

Резюме:

  • тип объединения: простой в реализации; только нижняя сторона должна затем проверить, какие из свойств не равны нулю.
  • Наследование: легко реализовать; может использовать полиморфизм или дискриминатор для обработки "что теперь?" Префикс типа
  • : немного более сложно реализовать, но обеспечивает большую гибкость и имеет нулевые накладные расходы в потоках TCP.

Ответ 2

Один из типичных вариантов заключается в том, чтобы сообщение обертки выполнялось как "тип параметра" или дискриминационный союз. У вас может быть перечисление (по одному на тип сообщения) и сообщение, содержащее поле с типом сообщения, а затем одно необязательное поле для типа сообщения.

Это описано в документации Protobuf как "union type" .

Ответ 3

Вы можете обернуть его вот так. Если данные будут содержать фактическое сообщение.

message MyCustomProtocol {
  required int32 protocolVersion = 1;
  required int32 messageType = 2;
  bytes data = 3;
}

Общее правило для протоколов - включить версию протокола. Вы будете очень рады, если у вас будут старые и новые клиенты.