首頁 > 後端開發 > Golang > 如何在沒有類型資訊的情況下解析未知的 Protobuf 訊息?

如何在沒有類型資訊的情況下解析未知的 Protobuf 訊息?

Patricia Arquette
發布: 2024-11-28 01:36:10
原創
653 人瀏覽過

How Can I Parse Unknown Protobuf Messages Without Type Information?

沒有類型資訊的未知Proto 訊息解組

雖然protobuf 的proto.Unmarshal() 方法需要已知的訊息類型,但未知消息提出了挑戰。但是,我們可以使用 protowire 套件提取有限的資訊。

方法:

  1. 使用 protowire.ConsumeField() 迭代未知的訊息負載。
  2. 標識欄位類型,可以為:

    • Varint
    • Fixed64
    • 位元組
    • StartGroup
    • Fixed32
  3. 根據欄位payload解析類型。
  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}}
登入後複製

注意事項:

  • 子訊息:
  • 子訊息:
  • 子訊息:
  • 子訊息:遞歸解析標識為訊息的位元組有效負載.
重複fields:

根據相同的欄位標籤編號進行處理。

Maps: 假設類似重複的 k/v 對。 Oneofs: Union類型資訊遺失,只有實際值雖然此程式碼沒有提供完整的生產級解決方案,但它提供了一種解析未知原始有效負載的方法,同時保留一些語意資訊。

以上是如何在沒有類型資訊的情況下解析未知的 Protobuf 訊息?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板