c# - protobuf-net 和重复字段

标签 c# java protocol-buffers protobuf-net

使用List作为protobuf中重复字段的对应项是否正确?我正在尝试这个,但总是遇到异常:

无效的线路类型;这通常意味着您已覆盖文件而没有截断或设置长度;请参阅Using Protobuf-net, I suddenly got an exception about an unknown wire-type

整个缓冲区是(第一个消息,下一个到达的消息附加到此): 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#中的Buffer和java中的Buffer是一样的。 当有 v3dDelta 字段时,一切都会按预期进行。

最佳答案

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

您尝试“使用长度前缀”读取它,但是: 9 作为 varint 前缀无效( 9 ,作为字段 header ,表示“字段 1,固定 64 位数据”,但是:在这种情况下它应该是一个 varint)。

实际上,您的数据没有9 兼容作为字段 header ,因为您的定义中没有任何 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 文件,但是......嗯),所以让我们调查一下:

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:经过更多调试后,部分是因为您(抱歉地说)破坏了 V3DDelta特性。您将它们定义为 int32在原型(prototype)中(字段 3 是数据中的变体),但您将它们实现为 double ...和doubleint32不是 friend 。

所以:

[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值,但这高度表明模式并不真正匹配,因此我认为正确的做法是在这种情况下更改类型。

关于c# - protobuf-net 和重复字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11080108/

相关文章:

java - 为什么 firePropertyChange(String propertyName, Object oldValue, Object newValue) protected 而不是公开的?

c++ - 如何使用 ZMQ 发送/接收使用 Protocol Buffers 序列化的二进制数据

node.js - GRPC微服务架构实现

c++ - QT 5.7 - 找不到 google/protobuf 文件 - 包含 PATH 错误

c# - 错误 : Could not load file or assembly 'Microsoft. ReportViewer.WebForms,版本 = 9.0.0.0

java - 使用指数解析字符串 (Java)

c# - Android RatingBar的MvvmCross实现

java - 如何在节点Firebase中获得唯一的随机产品?

c# - 由于 Service 的 'FaultedState',WCF.ServiceChannel 无法通信

c# - 使用 iTextSharp 提取 FlateDecode 图像