2011-04-14 145 views
3

我的问题是序列化C++中的protobuf数据并可能反序列化Java中的数据。 下面是我使用dcn提供的提示的代码:无法从Java中的C++反序列化protobuf数据

用这个,我在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; 
+0

你的代码是什么样子填充接收的数组? – jtahlborn 2011-04-15 00:33:48

+0

尝试打印出“message.SerializeAsString()”和“received”的结果并查看它们是否相同。 – 2011-04-15 01:12:15

+0

@jtahlborn我在我更新的问题中描述了它。请看一看。 – 2011-04-15 09:04:36

回答

3

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

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

在Java中,您可以直接通过parseDelimitedFrom(InputStream)writeDelimitedTo(OutputStream)来完成。你可以做同样的在C++中使用CodedOutputStream

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

看到一个豆蔻更复杂也this ealier thread.

+0

谢谢,这很有帮助。目前我序列化为std :: ostream并通过套接字发送。 name.SerializeToOStream(&os);和在Java中我读到它是这样的:NameProtos.Name.parseDelimitedFrom(socket.getInputStream());但我想它不会工作,不使用CodeOutputStream? – 2011-04-15 11:42:27

+0

'parseDelimitedFrom'预计首先读取大小,我想'SerializeToOStream'不会写大小,如果你只发送一条消息,这是没有问题的(在这种情况下使用'parseFrom'),否则你必须传输大小。 – dcn 2011-04-15 12:09:47

+0

这很棒,我有感觉我的方式是正确的,但是我仍然在Java方面遇到异常情况,您能否如此善待我在最后编辑原始问题的附件?这是我目前使用的代码, t知道我缺少什么 – 2011-04-15 12:22:16

0

你写了两件事情流,大小和Name对象,而只是试图读一。

作为一个普遍的问题:为什么你觉得需要使用CodedInputStream?引述docs

典型地,这些类将只为了进行编码和解码 协议缓冲区由协议缓冲器 库内部使用 。在 库的客户端只需要知道这个 类,如果他们想编写自定义 消息解析或序列化 程序

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

+0

这就是我所做的。我使用protobuf进行进程间通信这意味着,我使用它是消息传递服务。此外,我同意endian问题,但我找不到API文档如何使用替代方法。 – 2011-04-15 15:37:02

+0

@platzhirsch - 不知道那个评论意味着什么。但是,如果您将两件事写入流中,则需要阅读两件事。而你发布的代码只读一件事。 – Anon 2011-04-15 18:14:40