protobuf:从C#中读取C ++中的消息

我将阅读从C#服务器发送的,在C ++客户端的套接字中连续存储的消息。 我希望我可以阅读这样的消息的大小:

google::protobuf::uint32 m;
coded_input->ReadVarint32(&m);
cout << m << endl;

然后我想读取消息:

Person person;
CodedInputStream::Limit limit = coded_input->PushLimit(m);
person.ParseFromCodedStream(coded_input);
coded_input->PopLimit(limit);

C#代码如下所示:

var person = new Person { Id = 123456, Name = "Fred", Address = new Address { Line1 = "Flat 1", Line2 = "The Meadows ar garą " } };
Stream str = new NetworkStream(socket);
Serializer.SerializeWithLengthPrefix(str, person, PrefixStyle.Fixed32);

它不起作用。

我得到了C ++错误(43是cout << m << endl;)的结果(id,name,address是Person中的所有字段)

43

libprotobuf ERROR google / protobuf / message_lite.cc:123]无法解析类型为“Person”的邮件,因为它缺少必填字段:id,name,address

当我没有阅读变体并从coded_input解析消息时,一切正常(当我将SerializeWithLengthPrefix更改为在服务器代码中序列化时)。 不过,我需要一种方法来区分连续的消息,所以我需要知道我要读取的消息的大小。 我只是不知道如何发送尺寸。

我试过了:

Stream buf = new MemoryStream();
Serializer.Serialize(buf, person);
ProtoWriter writer = new ProtoWriter(str, null);
ProtoWriter.WriteInt32((int)buf.Length, writer);

但后来我得到:

未处理的异常:ProtoBuf.ProtoException:使用导线类型无效的序列化操作ProtoBuf.ProtoWriter.WriteInt32(Int32值,ProtoBuf.ProtoWriter写入器)位置0无[0x00000] in:0
在protobuftest.MainClass.Main(System.String [] args)中的[0x00097] /home/lorddidger/studia/csharp/protobuf-test/protobuf-test/Main.cs:31

我无法以这种方式发送任何int。 哪里不对?


更新:其实,我的目标是找到一种方法来传输一个整数(大小)与protobuf。 我需要任何示例(包括C ++和C#)如何处理,因为我不了解protobuf中的所有细节。

我注意到SerializeWithLengthPrefix发送的前缀(4 uint32)看起来像:size 0 0 0.大小是序列化后消息的字节数(我猜)。 我认为PrefixStyle.Fixed32说消息前只有一个uint32,但有4个!

最后,我认为你应该使用ProtoWriter.WriteInt32((int)buf.Length,writer)来传递整数,因为我遵循互联网上的somwhere的建议,我认为这是一个与C ++相关的解决方法。 现在我看到你不应该写varnish - 他们与引擎有关,而且花时间复杂。

我应该用int发送消息吗? 我应该如何区分第一个存储大小的下一个消息?

我看到C#可以hadle前缀很好,但有没有任何兼容的C + +和C#方式来说明消息的大小? 否则,没有办法排队消息,我会发现不合理的。


你的第一个例子只包括一个长度; “带长度前缀”实际上是以protobuf兼容的流进行编码的。

如果你是从c ++解码,请阅读两个varints; 首先是场号和线型; 第二个是长度。 第一个是打包成3比特线型,其余的是场号。 您也可以指定字段0跳过 - 如果没有检查,我不记得。


更新; 我检查了这一点,写入没有字段编号(只是varint长度前缀)的数据,然后使用两个不同的API(分别使用Deserialize)和通过DeserializeItems作为可枚举块读取C#中的数据。 我不得不修复后者中的一个错误,但是下面的代码将会在下一次代码推送时起作用(注意:只有阅读代码有修正,所以如果你用C#编写并且用C ++阅读,这不会影响你):

using (var ms = new MemoryStream())
{
    // write data with a length-prefix but no field number
    Serializer.SerializeWithLengthPrefix(ms, new Foo { Bar = 1 }, PrefixStyle.Base128, 0);
    Serializer.SerializeWithLengthPrefix(ms, new Foo { Bar = 2 }, PrefixStyle.Base128, 0);
    Serializer.SerializeWithLengthPrefix(ms, new Foo { Bar = 3 }, PrefixStyle.Base128, 0);

    ms.Position = 0;
    Assert.AreEqual(9, ms.Length, "3 lengths, 3 headers, 3 values");

    // read the length prefix and use that to limit each call
    TypeModel model = RuntimeTypeModel.Default;
    int len, fieldNumber, bytesRead;
    List<Foo> foos = new List<Foo>();
    do
    {
        len = ProtoReader.ReadLengthPrefix(ms, false, PrefixStyle.Base128, out fieldNumber, out bytesRead);
        if (bytesRead <= 0) continue;

        foos.Add((Foo)model.Deserialize(ms, null, typeof(Foo), len));

        Assert.IsTrue(foos.Count <= 3, "too much data!");
    } while (bytesRead > 0);

    Assert.AreEqual(3, foos.Count);
    Assert.AreEqual(1, foos[0].Bar);
    Assert.AreEqual(2, foos[1].Bar);
    Assert.AreEqual(3, foos[2].Bar);

    // do it using DeserializeItems
    ms.Position = 0;

    foos.Clear();
    foreach (var obj in model.DeserializeItems<Foo>(ms, PrefixStyle.Base128, 0))
    {
        foos.Add(obj);
        Assert.IsTrue(foos.Count <= 3, "too much data!");
    }
    Assert.AreEqual(3, foos.Count);
    Assert.AreEqual(1, foos[0].Bar);
    Assert.AreEqual(2, foos[1].Bar);
    Assert.AreEqual(3, foos[2].Bar);
}
链接地址: http://www.djcxy.com/p/7355.html

上一篇: protobuf: read a message in C++ from C#

下一篇: how to include javascript libraries in my own script