问题描述
|
我的问题是在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;
解决方法
我不知道Java代码中的“ 4”是什么,但是您的问题可能是由于字符集转换引起的。还要注意,protobuf在序列化时不会分隔消息。
因此,您应该使用原始数据来传输消息(字节数组或直接从/到流(反)序列化)。
如果您打算发送许多邮件,则在发送实际邮件之前,还应该发送大小。
在Java中,您可以直接通过
parseDelimitedFrom(InputStream)
和writeDelimitedTo(OutputStream)
进行操作。您可以使用CodedOutputStream
在C ++中完成相同的操作,但复杂得多,例如
codedOutput.WriteVarint32(protoMessage.ByteSize());
protoMessage.SerializeToCodedStream(&codedOutput);
另请参见该线程。
,您正在向流中写入两件事,一个大小和一个“ 9”对象,但仅尝试读取其中一个。
作为一个普遍的问题:为什么您觉得需要使用CodedInputStream?引用文档:
通常,这些类将仅
由协议缓冲区内部使用
库以进行编码和解码
协议缓冲区。客户
图书馆只需要知道这一点
如果他们想写习俗的话
消息解析或序列化
程序
并强调jtahlborn的评论:为什么选择低端字节序? Java处理big-endian值,因此必须在读取时进行转换。