无法从Java中的C ++反序列化protobuf数据

时间:2011-04-14 23:13:12

标签: java c++ protocol-buffers

我的问题是用C ++序列化protobuf数据并用Java反序列化数据。 这是我用于dcn:

给出的提示的代码

有了这个,我用C ++创建protobuf数据并将其写入通过套接字发送的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 个答案:

答案 0 :(得分:3)

我不知道您的Java代码中是什么received,但您的问题可能是由于某些字符集转换造成的。另请注意,protobuf在序列化时不会分隔消息。

因此,您应该使用原始数据来传输消息(字节数组或直接(反)串行化到/到流)。 如果您打算发送许多消息,您还应该在发送实际消息之前发送大小。

在Java中,您可以通过parseDelimitedFrom(InputStream)writeDelimitedTo(OutputStream)直接进行。您可以使用CodedOutputStream之类的

在C ++中执行相同的操作
codedOutput.WriteVarint32(protoMessage.ByteSize());
protoMessage.SerializeToCodedStream(&codedOutput);

另见this ealier thread.

答案 1 :(得分:0)

您正在向流写入两个内容,即大小和Name对象,但只是尝试读取一个。

作为一般问题:为什么你觉得需要使用CodedInputStream?引用docs

  

通常这些类只会是   由协议缓冲区内部使用   库以便编码和解码   协议缓冲区。客户的   图书馆只需知道这一点   如果他们想写自定义课程   消息解析或序列化   程序

并强调 jtahlborn 的评论:为什么小端? Java处理大端值,因此必须在读取时进行转换。