Здесь приведены правила кодирования: https://developers.google.com/protocol-buffers/docs/encoding
По сути, каждое поле кодируется как заголовок поля (он же «тег»), за которым следует полезная нагрузка. Заголовок поля представляет собой «varint» (см. Руководство по кодированию), значением которого является целое число, состоящее из номера поля и типа проводника. Тип проводника - это 3 младших значащих бита, а номер поля - остаток (сдвинут на 3 бита). В случае 0x0A (двоичный 1010) тип провода равен 2 (двоичный 010), а номер поля равен 1.
Способ обработки полезной нагрузки зависит от типа провода. Для типа проводов 2 (с префиксом длины) следует ожидать следующее:
- переменная, которая является длиной полезной нагрузки в байтах, затем
- столько байтов фактической полезной нагрузки
К сожалению, protobuf неоднозначен без схемы, поэтому знание того, что у вас есть данные с префиксом длины, не говорит вам, что это за данные ; полезная нагрузка с префиксом длины может быть:
- строка UTF-8
- необработанный BLOB (
bytes
) - под-сообщение
- «упакованный» массив некоторого примитивного типа (целые числа / числа с плавающей запятой / et c) - помня, что префикс длины - это число байтов , а не количество элементов; элементы даже не обязательно имеют фиксированный размер (сами они могут быть varints
Во многих случаях цель типа проводника не состоит в том, чтобы рассказать вам, как интерпретировать данные; это чтобы рассказать вам, как пропустить (или просто дословно сохранить) поле, если оно не является тем, о котором вы знаете. Например, кто-то еще использует V3 API, и вы только что обновили свою схему до V2 ; они отправляют сообщение V3 в API V2; в V3 есть дополнительные поля, которые вам не нужны - десериализатор не должен разрываться при попадании на них, поэтому тип проводника сообщает ему , как игнорировать поле (то есть, каковы правила для поиска следующего поля.) В противном случае мы могли бы просто использовать информацию схемы и не сохранять тип провода в полезной нагрузке вообще (хотя это также используется в качестве оптимизации при повторном примитивные данные, через «упакованные» массивы - это зависит от сериализатора, кодирует ли он, например, префикс длины или множество пар заголовок / значение поля).