首页 > 后端开发 > Golang > 如何在 Go 中解组未知的 Protobuf 消息?

如何在 Go 中解组未知的 Protobuf 消息?

Barbara Streisand
发布: 2024-11-30 09:21:13
原创
945 人浏览过

How Can I Unmarshal Unknown Protobuf Messages in Go?

解组未知 Protobuf 消息的陷阱

proto.Unmarshal 无法处理 interface{} 类型是需要理解的一个重要方面。它的方法签名规定传递一个 proto.Message 参数,该参数由具体的 protobuffer 类型实现。

克服挑战

处理缺乏额外上下文的原始 protobuffer 有效负载时,在字节切片旁边至少有一些标识信息(例如字符串或数字)至关重要。该信息可用于映射到特定的 protobuffer 具体消息。然后,您可以使用 switch 语句实例化适当的类型并将其传递给 Unmarshal:

switch atLeastSomething {
    case "foo":
        message = &mypb.Foo{}
    case "bar":
        message = &mypb.Bar{}
}
_ = proto.Unmarshal(data, message)
登录后复制

拥抱不可预测:解码完全未知的消息

在极少数情况下,您可能会遇到完全未知的 protobuffer 有效负载。 protowire 包提供了一种从中提取一些信息的解决方案,尽管存在固有的局限性。可以检索有效负载内容,但语义较弱。

实现细节

这是未知原始消息的简化解析器:

func parseUnknown(b []byte) []Field {
    // Data model
    type Field struct {
        Tag Tag
        Val Val
    }
    type Tag struct {
        Num int32
        Type protowire.Type
    }
    type Val struct {
        Payload interface{}
        Length  int
    }
    // Parsing algorithm
    fields := make([]Field, 0)
    for len(b) > 0 {
        n, t, fieldlen := protowire.ConsumeField(b)
        if fieldlen < 1 {
            return nil
        }
        ... // Parsing logic
        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;
}
&test.Foo{A: "A", B: "B", Bar: &test.Bar{C: "C"}}
登录后复制

输出将是:

Field{Tag:Tag{Num:1, Type:2}, Val:Val{Payload:[]uint8{0x41}, Length:1}}
Field{Tag:Tag{Num:2, Type:2}, Val:Val{Payload:[]uint8{0x42}, Length:1}}
Field{Tag:Tag{Num:1, Type:2}, Val:Val{Payload:[]uint8{0x43}, Length:1}}
Field{Tag:Tag{Num:3, Type:2}, Val:Val{Payload:[]Field{Field{Tag:Tag{Num:1, Type:2}, Val:Val{Payload:[]uint8{0x43}, Length:1}}}, Length:3}}
登录后复制

其他注意事项

  • 如果有效,子消息将被递归解析和存储。否则,字节按原样存储。
  • 重复字段不会被显式处理,但可以从解析后重复的 Tag.Num 值推断出来。
  • 映射在语义上应等同于重复的键/值对。
  • 其中一个信息可能会丢失,仅保留集合

替代方案:Any 和 Interface{}

虽然 Any 最初看起来像是未知消息的合适选项,但它具有严格定义的结构,并且不能用于解码未知的有效负载。此外,由于其特殊的结构,protowire 不适用于 Any。

以上是如何在 Go 中解组未知的 Protobuf 消息?的详细内容。更多信息请关注PHP中文网其他相关文章!

来源:php.cn
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
作者最新文章
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板