Rumah  >  Artikel  >  pembangunan bahagian belakang  >  Bolehkah saya menggunakan semula perduaan protobuf sedia ada semasa menyusun mesej yang mengandunginya? (protobuf3)

Bolehkah saya menggunakan semula perduaan protobuf sedia ada semasa menyusun mesej yang mengandunginya? (protobuf3)

WBOY
WBOYke hadapan
2024-02-06 10:30:11479semak imbas

在编组包含它的消息时,我可以重用现有的 protobuf 二进制文件吗?(protobuf3)

Kandungan soalan

protobuf ditakrifkan seperti berikut:

syntax = "proto3"

message hugemessage {
    // omitted
}

message request {
    string name = 1;
    hugemessage payload = 2;
}

Dalam satu kes, saya menerima hugemes​​sage,我想用其他字段打包它,然后将该消息传输给其他人。因此,我必须将 hugemes​​sage 二进制文件unmarshal放入go结构中,将其打包到request中,然后再次marshal。由于 hugemes​​sage 的 hgue 大小,unmarshalmarshal 的成本难以承受。那么我可以重用 hugemes​​sage binari daripada seseorang tanpa mengubah definisi protobuf?

func main() {
    // receive it from file or network, not important.
    bins, _ := os.ReadFile("hugeMessage.dump")
    var message HugeMessage
    _ = proto.Unmarshal(bins, &message) // slow
    request := Request{
        name: "xxxx",
        payload: message,
    }
    requestBinary, _ := proto.Marshal(&request) // slow
    // send it.
    os.WriteFile("request.dump", requestBinary, 0644)
}


Jawapan Betul


Jawapan ringkasnya ialah: Tidak, tiada cara mudah atau standard untuk mencapai ini.

Strategi yang paling jelas ialah melakukannya seperti yang anda lakukan sekarang - unmarshal hugemes​​sage,将其设置为 request dan kemudian marshal lagi. Permukaan API protobuf Golang tidak benar-benar menyediakan cara untuk melakukan lebih banyak - dan untuk alasan yang baik.

Maksudnya, terdapat cara untuk mencapai apa yang anda mahu lakukan. Tetapi ini tidak semestinya selamat atau boleh dipercayai, jadi anda perlu menimbang kos itu dengan apa yang anda miliki sekarang.

Satu cara untuk mengelakkan pembongkaran adalah dengan memanfaatkan cara mesej biasanya bersiri

message request {
    string name = 1;
    hugemessage payload = 2;
}

..bersamaan dengan

message request {
    string name = 1;
    bytes payload = 2;
}

.. mana payload 包含针对某些 hugemes​​sage 调用 marshal(...) hasilnya.

Jadi, jika kita mempunyai definisi berikut:

syntax = "proto3";

message hugemessage {
  bytes field1 = 1;
  string field2 = 2;
  int64 field3 = 3;
}

message request {
  string name = 1;
  hugemessage payload = 2;
}

message rawrequest {
  string name = 1;
  bytes payload = 2;
}

Kod berikut:

req1, err := proto.Marshal(&pb.Request{
    Name: "name",
    Payload: &pb.HugeMessage{
        Field1: []byte{1, 2, 3},
        Field2: "test",
        Field3: 948414,
    },
})
if err != nil {
    panic(err)
}

huge, err := proto.Marshal(&pb.HugeMessage{
    Field1: []byte{1, 2, 3},
    Field2: "test",
    Field3: 948414,
})
if err != nil {
    panic(err)
}

req2, err := proto.Marshal(&pb.RawRequest{
    Name:    "name",
    Payload: huge,
})
if err != nil {
    panic(err)
}

fmt.Printf("equal? %t\n", bytes.Equal(req1, req2))

Output equal? true

Tidak jelas sama ada "kebiasaan" ini boleh dipercayai sepenuhnya, dan tiada jaminan ia akan terus berfungsi selama-lamanya. Jelas sekali rawrequest 类型必须完全镜像 request jenis, ini tidak sesuai.

Pilihan lain ialah membina mesej dengan cara yang lebih manual, iaitu menggunakan pakej protowire - sekali lagi, jangan ragu, berhati-hati disyorkan.

Atas ialah kandungan terperinci Bolehkah saya menggunakan semula perduaan protobuf sedia ada semasa menyusun mesej yang mengandunginya? (protobuf3). Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:stackoverflow.com. Jika ada pelanggaran, sila hubungi admin@php.cn Padam