使用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
...和double
和int32
不是 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/