Невозможно десериализовать данные protobuf из C ++ в Java - PullRequest
3 голосов
/ 15 апреля 2011

Моя проблема состоит в том, чтобы сериализовать данные protobuf в C ++ и десериализовать данные в Java, вероятно. Вот код, который я использую для подсказок, данных dcn:

С этим я создаю данные protobuf в C ++ и записываю их в ostream, который отправляется через сокет.

Name name;
name.set_name("platzhirsch");

boost::asio::streambuf b;
std::ostream os(&b);

ZeroCopyOutputStream *raw_output = new OstreamOutputStream(&os);
CodedOutputStream *coded_output = new CodedOutputStream(raw_output);

coded_output->WriteLittleEndian32(name.ByteSize());
name.SerializeToCodedStream(coded_output);
socket.send(b);

Это сторона Java, где я пытаюсь ее проанализировать:

NameProtos.Name name = NameProtos.Name.parseDelimitedFrom(socket.getInputStream());
System.out.println(name.newBuilder().build().toString());

Однако этим я получаю это исключение: com.google.protobuf.UninitializedMessageException: в сообщении отсутствуют обязательные поля: имя

Чего мне не хватает?


Неправильная строка кода: name.newBuilder().build().toString()

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

И последнее, что мне сказали в списке рассылки protobuf: чтобы очистить CodedOutputStreams, объекты должны быть удалены!

delete coded_output;
delete raw_output;

Ответы [ 2 ]

3 голосов
/ 15 апреля 2011

Я не знаю, что такое received в вашем Java-коде, но ваша проблема может быть связана с некоторым преобразованием кодировки. Также обратите внимание, что protobuf не разделяет сообщения при сериализации.

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

В Java вы можете сделать это напрямую через parseDelimitedFrom(InputStream) и writeDelimitedTo(OutputStream). Вы можете сделать то же самое в C ++, немного сложнее, используя CodedOutputStream как

codedOutput.WriteVarint32(protoMessage.ByteSize());
protoMessage.SerializeToCodedStream(&codedOutput);

См. Также эту более раннюю тему.

0 голосов
/ 15 апреля 2011

Вы пишете две вещи в поток, размер и объект Name, но пытаетесь прочитать только одну.

Как общий вопрос: почему вы чувствуете необходимость использовать CodedInputStream? Цитировать документы :

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

И чтобы подчеркнуть комментарий jtahlborn : почему little-endian? Java имеет дело со значениями с прямым порядком байтов, поэтому при чтении придется конвертировать.

...