2011-04-14 146 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