2011-06-03 92 views
2

在將消息序列化到套接字(SerializeToFileDescritor)之後,C++客戶端和C#服務器之間的簡單通信陷入困境。protobuf:連續序列化和反序列化到套接字

C++客戶端:

Person person; 
    person.set_id(54321); 
    person.set_name("bla"); 
    person.mutable_address()->set_line1("sdfa"); 
    person.mutable_address()->set_line2("asdfsdfa"); 

    cout << person.id() << endl << person.name() << endl; 
    cout << person.address().line2() << endl; 

    person.SerializeToFileDescriptor(s); 

    ZeroCopyInputStream* raw_input = new FileInputStream(s); 
    CodedInputStream* coded_input = new CodedInputStream(raw_input); 

    Person person2; 

    person2.ParseFromFileDescriptor(s); 

    cout << person2.id() << endl << person2.name() << endl; 
    cout << person2.address().line2() << endl; 

C#服務器

var sockServer = new TcpListener(2048); 
sockServer.Start(); 

var person = new Person { Id = 123456, Name = "Fred", Address = new Address { Line1 = "Flat 1", Line2 = "The Meadows ar garą " } }; 

var socket = sockServer.AcceptSocket(); 
Stream str = new NetworkStream(socket); 

var response = Serializer.Deserialize<Person>(str); 
Console.WriteLine(response.Id); 

Serializer.Serialize(str, person); 

在我看來可笑愚蠢這是行不通的。

如果我刪除以下任何一個:person.SerializeToFileDescriptor(s)或person2.ParseFromFileDescriptor(s),另一個將工作。

我應該怎麼做才能讓它們同時工作?

回答

2

根對象的默認行爲將消耗所有數據到流尾。而且由於您不關閉流,因此永遠不會到來。

如果你的意圖是將多個對象向同一個套接字發送(這很正常),那麼你需要給它一個線索。最常見的方法是在每個消息前加上要發送的數據的長度。這可能是一個固定的32 int,或者如果方便的話varint。然後你可以在消費者那裏閱讀。

你如何處理,取決於調用者; protobuf-net有一個DeserializeWithLengthPrefix,它將處理各種形式的編碼,帶或不帶附加的字段標記(在varint的情況下,使其成爲有效的protobuf流)。例如:

Person person = Serializer.DeserializeWithLengthPrefix<Person>(str, 
     PrefixStyle.Fixed32, 0); 
+0

我在C#服務器中將反序列化更改爲DeserializeWithLengthPrefix,但我應該如何調整C++客戶端?我嘗試模仿像這樣添加uint32的前綴:person.ByteSize()0 0 0。沒有成功。 – 2011-06-03 22:48:12

+0

@lord - 我不是一個C++大師,我害怕 - 但我希望*它可以很容易地獲得數據的長度。如果這就是'person.ByteSize()',那麼太好了!我需要確切地知道結果是什麼 - 即ByteSize()是否導致一個字節?或4? (即我們是否需要零) – 2011-06-03 23:18:58

2

如果您打算髮送多個郵件,this可能會有用。