我的问题是用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;
答案 0 :(得分:3)
我不知道您的Java代码中是什么received
,但您的问题可能是由于某些字符集转换造成的。另请注意,protobuf在序列化时不会分隔消息。
因此,您应该使用原始数据来传输消息(字节数组或直接(反)串行化到/到流)。 如果您打算发送许多消息,您还应该在发送实际消息之前发送大小。
在Java中,您可以通过parseDelimitedFrom(InputStream)
和writeDelimitedTo(OutputStream)
直接进行。您可以使用CodedOutputStream
之类的
codedOutput.WriteVarint32(protoMessage.ByteSize());
protoMessage.SerializeToCodedStream(&codedOutput);
答案 1 :(得分:0)
您正在向流写入两个内容,即大小和Name
对象,但只是尝试读取一个。
作为一般问题:为什么你觉得需要使用CodedInputStream?引用docs:
通常这些类只会是 由协议缓冲区内部使用 库以便编码和解码 协议缓冲区。客户的 图书馆只需知道这一点 如果他们想写自定义课程 消息解析或序列化 程序
并强调 jtahlborn 的评论:为什么小端? Java处理大端值,因此必须在读取时进行转换。