2

protobuf の繰り返しフィールドの対応物として List を使用するのは正しいですか? 私はこれを試していますが、常に例外が発生しました:

ワイヤ タイプが無効です。これは通常、切り詰めたり長さを設定したりせずにファイルを上書きしたことを意味します。Protobuf-net の使用を参照してください。未知のワイヤ タイプに関する例外が突然発生しました。

バッファ全体は次のとおりです (最初のメッセージ、次に到着するメッセージがこれに追加されます): 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 フィールドがあった場合、すべてが期待どおりに機能します。

4

1 に答える 1

2

はい、List<T>または配列(T[])のいずれかが。に対して機能しrepeatedます。ちなみに、.proto定義からprotobuf-netクラスを生成するためのツールがあります。

「長さプレフィックス付き」で読み込もうとしていますが、9varintプレフィックスとしては無効です(9フィールドヘッダーとしては、「フィールド1、固定64ビットデータ」を意味します。ただし、このコンテキストでは、varint)。

実際には、フィールドとしての定義に649ビット値がないため、フィールドヘッダーとして互換性のあるデータはありません1。asフィールドがあります。これはうまく機能しますがフィールドヘッダーとして機能します。double373

シーケンス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)、それを調査しましょう:

int len = ProtoReader.DirectReadVarintInt32(ms);

これで99バイトが残っているので、見栄えがします...

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それらをプロトのように定義しましたが(フィールド3はデータの変数です)、それらをdouble...として実装し、友達ではdoubleありint32ません。

それで:

[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に値のaを受け入れさせることができますが、これはスキーマが実際には一致しないことを強く示しているため、この場合はタイプを変更するのが正しいと思います。varintdouble

于 2012-06-18T12:48:01.103 に答える