为了账号安全,请及时绑定邮箱和手机立即绑定

可以将 protobuf 编组消息发送到已分配的字节数组而无需复制吗?

可以将 protobuf 编组消息发送到已分配的字节数组而无需复制吗?

Go
慕妹3146593 2023-06-01 15:17:39
我正在通过自定义数据包实现客户端服务器通信。我正在使用围棋net.conn。可以拨号tcp/unix schemes,非常方便。我用来protocol buffer定义我的消息。我定义了一个包含length和buffertype Packet struct {    length uint32    buffer []byte}API函数是这样的:func(api *API) Send(m *proto.Message) errorfunc(api *API) Receive(p *Packet) error以send函数为例,它接收一个 protobuf 消息,将其编组为Packet. 并将其写入net.conn.下面是 Send 函数的简化版本:func(api *API) Send(m *proto.Message) error {    bytes, err := proto.Marshal(m)    if err != nil {        return err    }    buffer := api.packet[:length]    copy(buffer, bytes)    _, err := api.conn.Write(buffer)    if err != nil {        return err    }    return nil}我正在复制bytes到buffer. 因为 Go protocol buffer API 只提供func Marshal(pb Message) ([]byte, error)在 Protocol Buffer C++ 中,它提供了 bool SerializeToArray(void * data, int size) const,它正在序列化消息并将其存储在给定的字节数组中。但是我在 Go protocol buffer API 中找不到同样的东西。如果我想直接将序列化结果存储在给定的字节数组中,有什么办法可以避免复制?
查看完整描述

3 回答

?
慕田峪9158850

TA贡献1794条经验 获得超7个赞

您正在寻找来自 的MarshalTo方法gogo/protobuf,它是 protobuf 的另一种实现,与原始方法兼容。

当您将要填充的缓冲区传递给它时,您可以通过多个编组调用重新使用同一个缓冲区。显然缓冲区应该足够大。

func MarshalTo([]byte, m) error


查看完整回答
反对 回复 2023-06-01
?
慕码人2483693

TA贡献1860条经验 获得超9个赞

似乎你可以Packet.buffer成为一个proto.Buffer

type Packet struct {

    length uint32

    buffer proto.Buffer

}

...

var packet Packet

packet.length = YouLength

packet.buffer = proto.NewBuffer(make([]byte, YouLength))

//Then you can Marshall in Packet directly and it  may be reused.

err := packet.Marshal(message)


查看完整回答
反对 回复 2023-06-01
?
RISEBY

TA贡献1856条经验 获得超5个赞

目前尚不清楚你在问什么。请注意,原型 Marshal() 函数完全符合您的要求:它将消息序列化为字节切片(您可能指的是字节数组)


看看这些是否有帮助:


func(api *API) Send(m *proto.Message) error {

    p := Packet{}

    p.buffer, err := proto.Marshal(m)

    if err != nil {

        return err

    }

    _, err := api.conn.Write(p.buffer)

    if err != nil {

        return err

    }

    return nil

}

或者


func(api *API) Send(m *proto.Message) error {

    buffer := api.packet[:length]

    buffer, err := proto.Marshal(m)

    if err != nil {

        return err

    }

    _, err := api.conn.Write(buffer)

    if err != nil {

        return err

    }

    return nil

}


查看完整回答
反对 回复 2023-06-01
  • 3 回答
  • 0 关注
  • 125 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信