ホームページ >バックエンド開発 >Golang >型情報のない不明な Protobuf メッセージを解析するにはどうすればよいですか?

型情報のない不明な Protobuf メッセージを解析するにはどうすればよいですか?

Patricia Arquette
Patricia Arquetteオリジナル
2024-11-28 01:36:10641ブラウズ

How Can I Parse Unknown Protobuf Messages Without Type Information?

タイプ情報を使用しない不明な Proto メッセージのデマーシャリング

protobuf の proto.Unmarshal() メソッドには既知のメッセージ タイプが必要ですが、不明なメッセージには課題が伴います。ただし、protowire パッケージを使用すると、限られた情報を抽出できます。

アプローチ:

  1. protowire.ConsumeField() を使用して、未知のメッセージ ペイロードを反復処理します。
  2. フィールドのタイプを特定します。 be:

    • Varint
    • Fixed64
    • Bytes
    • StartGroup
    • Fixed32
  3. フィールドを解析する
  4. ペイロードを再帰的に解析することでサブメッセージを処理します。

データモデル:

type Field struct {
    Tag Tag
    Val Val
}

type Tag struct {
    Num int32
    Type protowire.Type
}

type Val struct {
    Payload interface{}
    Length int
}

パーサー:

func parseUnknown(b []byte) []Field {
    // Iteratively consume and parse fields
    for len(b) > 0 {
        // Read field tag and length
        n, t, fieldlen := protowire.ConsumeField(b)
        if fieldlen < 1 {
            return nil
        }
        field := Field{Tag: Tag{Num: int32(n), Type: t}}

        // Read and process tag and value content
        _, _, taglen := protowire.ConsumeTag(b[:fieldlen])
        if taglen < 1 {
            return nil
        }
        var v interface{}
        var vlen int
        switch t {
            case protowire.VarintType:
                v, vlen = protowire.ConsumeVarint(b[taglen:fieldlen])
            case protowire.Fixed64Type:
                v, vlen = protowire.ConsumeFixed64(b[taglen:fieldlen])
            case protowire.BytesType:
                v, vlen = protowire.ConsumeBytes(b[taglen:fieldlen])
                sub := parseUnknown(v.([]byte))
                if sub != nil {
                    v = sub
                }
            case protowire.StartGroupType:
                v, vlen = protowire.ConsumeGroup(n, b[taglen:fieldlen])
                sub := parseUnknown(v.([]byte))
                if sub != nil {
                    v = sub
                }
            case protowire.Fixed32Type:
                v, vlen = protowire.ConsumeFixed32(b[taglen:fieldlen])
        }
        if vlen < 1 {
            return nil
        }

        field.Val = Val{Payload: v, Length: vlen - taglen}
        fields = append(fields, field)
        b = b[fieldlen:]
    }
    return fields
}

例 (メッセージ構造):

message Foo {
  string a = 1;
  string b = 2;
  Bar bar = 3;
}

message Bar {
  string c = 1;
}

例 (解析済み)出力):

main.Field{Tag:main.Tag{Num:1, Type:2}, Val:main.Val{Payload:[]uint8{0x41}, Length:1}}
main.Field{Tag:main.Tag{Num:2, Type:2}, Val:main.Val{Payload:[]uint8{0x42}, Length:1}}
main.Field{Tag:main.Tag{Num:1, Type:2}, Val:main.Val{Payload:[]uint8{0x43}, Length:1}}
main.Field{Tag:main.Tag{Num:3, Type:2}, Val:main.Val{Payload:[]main.Field{main.Field{Tag:main.Tag{Num:1, Type:2}, Val:main.Val{Payload:[]uint8{0x43}, Length:1}}}, Length:3}}

考慮事項:

  • サブメッセージ: メッセージとして識別されたバイト ペイロードの再帰解析.
  • 繰り返しフィールド: 同一のフィールド タグ番号に基づいて処理されます。
  • マップ: 繰り返される k/v ペアと同様であると想定されます。
  • Oneofs: 共用体型情報が失われ、実際の値のみが失われますparsed.

このコードは完全な運用グレードのソリューションを提供するものではありませんが、一部のセマンティック情報を保持しながら未知のプロト ペイロードを解析する方法を提供します。

以上が型情報のない不明な Protobuf メッセージを解析するにはどうすればよいですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。