开发者

protobuf: consecutive serialize and deserialize to/from socket

开发者 https://www.devze.com 2023-03-11 11:28 出处:网络
My simple communication between C++ client and C# server got stuck after a message was serialized to socket (SerializeToFileDescritor).

My simple communication between C++ client and C# server got stuck after a message was serialized to socket (SerializeToFileDescritor).

C++ client:

  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# server

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);
Consol开发者_如何学JAVAe.WriteLine(response.Id);

Serializer.Serialize(str, person);

It seems to me ridiculously stupid it doesn't work.

If I remove any one of these: person.SerializeToFileDescriptor(s) or person2.ParseFromFileDescriptor(s), the other will work.

What should I do to make them work both?


The default behaviour for a root object is to consume all data to the end of the stream. And since you don't close the stream, that end never comes.

If your intention is to send multiple objects down the same socket (which is pretty normal) then you need to give it a clue. The most common approach would be to prefix each message with the length of the data about to be sent. This could be in a fixed-32 int, or in a varint if convenient. You can then read that at the consumer.

How you then handle that depends on the caller; protobuf-net has a DeserializeWithLengthPrefix that will handle various forms of encoding, with-or-without an additional field marker (in the case of varint, to make it a valid protobuf stream). For example:

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


If you intend to send multiple messages, this might be useful.

0

精彩评论

暂无评论...
验证码 换一张
取 消