protobuf-net和重复的字段

时间:2012-06-18 09:27:18

标签: c# java protocol-buffers protobuf-net

使用List作为protobuf中重复字段的对应部分是否正确?我试过这个并且总是例外:

无效的线型;这通常意味着您在不截断或设置长度的情况下覆盖了文件;见Using Protobuf-net, I suddenly got an exception about an unknown wire-type

整个缓冲区是(第一个msg,下一个到达的附加到此):  9 8 5 26 5 24 238 98 32 1

java protobuf文件:

package XXX;

option java_package = "XXX";
option java_outer_classname = "Protos";

option optimize_for = SPEED;

message V3DDelta {
  optional int32 bid = 1;
  optional int32 bidSize = 2;
  optional int32 ask = 3;
  optional int32 askSize = 4;
}

message Request {
  optional int32 type = 1;
  optional string request = 2;
}

message Response {
  optional int32 type = 1;
  optional string response = 2;
  repeated V3DDelta v3dDelta = 3;
}

和protbuf-net类:

[ProtoContract]
public class V3DDelta {
    [ProtoMember(1)]
    public double bid { get; set; }
    [ProtoMember(2)]
    public int bidSize { get; set; }
    [ProtoMember(3)]
    public double ask { get; set; }
    [ProtoMember(4)]
    public int askSize { get; set; }
}

[ProtoContract]
public class Request {
    [ProtoMember(1)]
    public int Type { get; set; }
    [ProtoMember(2)]
    public string Rq { get; set; }
}

[ProtoContract]
public class Response {
    [ProtoMember(1)]
    public int Type { get; set; }
    [ProtoMember(2)]
    public string Rsp { get; set; }
    [ProtoMember(3)]
    public List<V3DDelta> v3dDelta { get; set; }
    public Response() {
        v3dDelta = new List<V3DDelta>();
    }
}

我尝试过V3DDelta [],但结果是一样的。 阅读信息:

Response rsp = Serializer.DeserializeWithLengthPrefix<Response>(rcvstream, PrefixStyle.Base128);

并在java消息中使用writeDelimitedTo发送。 c#中的缓冲区与java中的缓冲区完全相同。 当有na v3dDelta字段时,一切都按预期工作。

1 个答案:

答案 0 :(得分:1)

是的,List<T>或数组(T[])适用于repeated。顺便提一下,有一个工具可以从.proto定义生成protobuf-net类。

您试图以“长度前缀”读取它,但是:9 无效作为varint前缀(9,作为字段标题,表示“字段” 1,修复了64位数据“,但是:在这种情况下它应该是 varint )。

实际上,您的数据的9兼容,因为您在定义中没有任何64位值作为字段1 。你double作为字段3,这可以很好地完成工作 - 但是,73作为字段标题。

我会告诉你序列9,8,5,...代表什么,但是 - 我们会:

9 : field 1, fixed 64-bit
    8 5 26 5 24 238 98 32 <== payload for above
1 : field 0, fixed 64-bit
    ^^ not *really* valid, but fields <= 0 generally mean "stop" - but
       frankly this is not a clean/defined/expected exit condition

再次:请检查您的数据。这看起来不像protobuf流,或者至少不是与你的模式匹配的。


编辑:可能java writeDelimitedTo包括只是长度,没有标题)使它在技术上不是一致的protobuf文件,但是...... meh),所以让我们调查:< / p>

int len = ProtoReader.DirectReadVarintInt32(ms);

给了我们9,我们剩下9个字节,所以看起来不错......

8 : Field 1, varint
  5 = payload of above
26 : Field 3, length-delimited
  5 = length of payload
   24 238 98 32 1 = payload of ^^^
      24 : Field 3, varint
          238, 98 = payload of ^^^ = 12654
      32 : Field 4, varint
          1 = payload of ^^^ = 1

现在看起来它应该解析......调查它为什么不......


编辑2:经过一些调试之后,部分这是因为你(遗憾地说)borked V3DDelta属性。您在proto中将它们定义为int32(并且字段3是数据中的varint),但您将它们实现为double ... doubleint32是不是朋友。

所以:

[ProtoContract]
public class V3DDelta
{
    [ProtoMember(1)]
    public int bid { get; set; }
    [ProtoMember(2)]
    public int bidSize { get; set; }
    [ProtoMember(3)]
    public int ask { get; set; }
    [ProtoMember(4)]
    public int askSize { get; set; }
}

然后以下工作正常:

using (var ms = new MemoryStream(buffer))
{
    int len = ProtoReader.DirectReadVarintInt32(ms);
    var resp = (Response)model.Deserialize(ms, null, typeof(Response), len);

    Assert.AreEqual(5, resp.Type);
    Assert.AreEqual(1, resp.v3dDelta.Count);
    Assert.AreEqual(12654, resp.v3dDelta[0].ask);
    Assert.AreEqual(1, resp.v3dDelta[0].askSize);
}

从技术上讲,我可以使protobuf-net接受varint double值,但这高度表明模式不匹配,所以我认为在这种情况下改变类型是正确的。