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

我正在通过自定义数据包实现客户端服务器通信。
我正在使用Go net.conn </ 代码>。 它可以拨打tcp / unix方案,这非常方便。 我使用 protocol buffer </ code>定义消息。</ p>

我定义了一个包含 length </ code>和 buffer </ code>的数据包 </ p>

  type数据包结构{
长度uint32
缓冲区[] byte
}
</ code> </ pre>

API 函数是这样的:

func(api * API)Send(m * proto.Message)错误</ code>

func(api * API)Receive(p * 数据包)错误</ code> </ p>

send </ code>函数为例,它接收一个protobuf消息,将其封送为 Packet </ code> 。 并将其写入 net.conn </ code>。 </ p>

这是Send函数的简化版本:</ p>

  func(api * API)Send(m * proto.Message)错误 {
字节,错误:= proto.Marshal(m)
,如果错误!=无{
返回错误
}
缓冲区:= api.packet [:length]
复制(缓冲区,字节)\ n _,err:= api.conn.Write(buffer)
如果err!= nil {
return err
}
return nil
}
</ code> </ pre>

我正在将 bytes </ code>复制到 buffer </ code>中。 因为Go协议缓冲区API仅提供了

func Marshal(pb消息)([]字节,错误)</ code> </ p>

在协议缓冲区C ++中,它提供了
bool SerializeToArray(void * data,int size)const </ code>,用于对消息进行序列化并将其存储在给定的字节数组中。
但是我在Go协议缓冲区API中找不到相同的东西。 </ p>

如果我想直接将序列化结果存储在给定的字节数组中,是否可以避免复制? </ p>
</ div>

展开原文

原文

I am implementing client server communication by self defined packets. I am using Go net.conn. It can dial tcp/unix schemes which is very convenient. I use protocol buffer to define my messages.

I defined a Packet which contains length and buffer

type Packet struct {
    length uint32
    buffer []byte
}

The API function is like this:
func(api *API) Send(m *proto.Message) error
func(api *API) Receive(p *Packet) error

Take send function as an example, it takes in a protobuf message, marshal it into Packet. And write it to the net.conn.

Here is a simplified version of the Send function:

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
}

I was copying bytes into buffer. Because Go protocol buffer API only provides
func Marshal(pb Message) ([]byte, error)

In protocol buffer C++, it provides bool SerializeToArray(void * data, int size) const, which is serializing the message and storing it in the given byte array. But I can not find the same thing in Go protocol buffer API.

Is there any way to avoid the copy if I want to directly storing serialized result in the given byte array?

dongxianshuai8927
dongxianshuai8927 您能否澄清一些事情:为什么数据包存储在API的字段中,并且该长度来自何处?您是否真的想写一个由长度(4个字节)和实际连接消息组成的字节数组?
接近 2 年之前 回复

3个回答



不清楚您要问什么。 请注意,原型Marshal()函数完全可以满足您的需求:它将消息序列化为字节片(您可能用字节数组表示)</ p>

看看这些帮助之一 :</ p>

  func(api * API)Send(m * proto.Message)错误{
p:= Packet {}
p.buffer,err:= proto.Marshal (m)
如果err!= nil {
return err
}
_,err:= api.conn.Write(p.buffer)
如果err!= nil {
return err
}

返回nil
}
</ code> </ pre>

或</ p>

  func(api * API)Send(m * proto  .Message)错误{
缓冲区:= api.packet [:length]
缓冲区,错误:= proto.Marshal(m)
如果错误!=无{
返回错误
}
_,错误 := api.conn.Write(buffer)
if err!= nil {
return err
}
return nil
}
</ code> </ pre>
</ div>

展开原文

原文

It is not clear what you are asking. Notice that the proto Marshal() function does exactly what you are looking for: It serializes the message into a byte slice (what you probably mean by byte array)

See if either of these help:

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
}

Or

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
}

dongpao9165
dongpao9165 我的目的是将序列化缓冲区放入数据包中,而不是直接将其写入conn。 因为该数据包已被我的项目的其他组件使用。 我无法重构它。 proto.Marshal返回[] byte,并已复制到我的数据包中。 我正在寻找避免复制的方法。 一个示例是protobuf C ++ API,它可以将消息封送到已经分配的缓冲区中。 但是go protobuf只能退货。
接近 2 年之前 回复



似乎您可以将 Packet.buffer </ code>设为 proto.Buffer </ code> </ p>

  type 数据包结构{
长度uint32
缓冲区proto.Buffer
}
...
var数据包
packet.length = YouLength
packet.buffer = proto.NewBuffer(make([] byte,YouLength))\ n //然后您可以直接在Packet中使用Marshall,并且可以重复使用。
err:= packet.Marshal(message)
</ code> </ pre>
</ div>

展开原文

原文

Seems you can make Packet.buffer to be a 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)



您正在寻找 gogo / protobuf </ code>的marshalTo“ rel =” nofollow noreferrer“> MarshalTo 方法,与原始协议兼容。</ p>

您可以 当您将要传递的缓冲区传递给缓冲区时,请通过多个元帅调用重新使用相同的缓冲区。 显然缓冲区应该足够大。</ p>

  func MarshalTo([] byte,m)错误
</ code> </ pre>
</ div>

展开原文

原文

You're looking for MarshalTo method from gogo/protobuf, another implementation of protobuf, compatible with the original.

You can re-use the same buffer through multiple marshal calls as you pass it the buffer to be filled. Obviously the buffer should be big enough.

func MarshalTo([]byte, m) error 

Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问
相关内容推荐