Используя Protobuf-сеть, я внезапно получил исключение о неизвестном проводном типе

(это - пересообщение вопроса, который я видел в своем RSS, но который был удален OP. Я повторно добавил его, потому что я видел этот вопрос, который задают несколько раз в различных местах; Wiki для "хорошей формы")

Внезапно, я получаю a ProtoException когда десериализация и сообщение: неизвестный проводной тип 6

  • Что такое проводной тип?
  • Каковы различные значения проводного типа и их описание?
  • Я подозреваю, что поле вызывает проблему, как отладить это?
60
задан Marc Gravell 28 January 2010 в 07:38
поделиться

1 ответ

Первое, что нужно проверить:

Это ВКЛЮЧЕННАЯ ДАННЫЕ ПРОТОБУФА ДАННЫХ? Если вы попробуете разобрать другой формат (json, xml, csv, двоичный) или просто разбитые данные (например, "ошибка внутреннего сервера" html текстовой страницы с запятой), то это не сработает.


Что такое wire-type?

Это 3-битный флаг, который говорит ему (в широком смысле; в конце концов, это всего 3 бита), как выглядят следующие данные.

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

Каковы различные значения проводного типа и их описание?

  • 0: целое число переменной длины (до 64 бит) - base-128, закодированное с MSB-индикатором продолжения (используется по умолчанию для целочисленных типов, включая перечисления)
  • 1: 64-битное - 8 байт данных (используется для double, или electively для long/ulong)
  • 2: length-prefixed - сначала считывается целое число в кодировке переменной длины; это говорит о том, сколько байт данных следует (используется для строк, байт[], "упакованные" массивы, а по умолчанию для дочерних объектов свойства/списки)
  • 3: "стартовая группа" - альтернативный механизм кодирования дочерних объектов, использующий теги start/end - в значительной степени устаревший от Google, пропустить целое детское поле объекта дороже, так как нельзя просто "искать" мимо неожиданного объекта
  • 4: "конечная группа" - двойная с 3
  • 5: 32-битная - 4 байта данных (используется для float, или electively для int/uint и других малых целочисленных типов)

Я подозреваю, что какое-то поле вызывает проблему, как это отладить?

Вы сериализуете в файл? Скорее всего причина (по моему опыту) в том, что Вы перезаписали существующий файл, но не усекали его; т.е. он был 200 байт; Вы переписали его, но только 182 байта. Теперь в конце вашего потока есть 18 байт мусора, который его отключает. Файлы должны быть усечены при перезаписи буферов протокола. Вы можете сделать это с помощью FileMode:

using(var file = new FileStream(path, FileMode.Truncate)) {
    // write
}

или с помощью SetLength after write your data:

file.SetLength(file.Position);

Other possible cause

You are (accidentally) deserializing a stream into a different type than what was serialized (случайно). Стоит перепроверить обе стороны разговора, чтобы убедиться, что этого не произошло.

56
ответ дан 24 November 2019 в 17:45
поделиться
Другие вопросы по тегам:

Похожие вопросы: