我正在通过自定义数据包实现客户端服务器通信。
我正在使用Go net.conn
。它可以拨打tcp / unix方案,这非常方便。我使用protocol buffer
定义我的消息。
我定义了一个包含length
和buffer
的数据包
type Packet struct {
length uint32
buffer []byte
}
API函数如下:
func(api *API) Send(m *proto.Message) error
func(api *API) Receive(p *Packet) error
以send
函数为例,它接收一个protobuf消息,并将其封送到Packet
中。并将其写入net.conn
。
以下是“发送”功能的简化版本:
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协议缓冲区API仅提供
func Marshal(pb Message) ([]byte, error)
在协议缓冲区C ++中,它提供了
bool SerializeToArray(void * data, int size) const
,它正在序列化消息并将其存储在给定的字节数组中。
但是我在Go协议缓冲区API中找不到相同的东西。
如果我想直接将序列化结果存储在给定的字节数组中,是否可以避免复制?
答案 0 :(得分:0)
不清楚您要问什么。注意,原型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
}
答案 1 :(得分:0)
似乎您可以使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)
答案 2 :(得分:0)
您正在从gogo/protobuf
寻找MarshalTo方法,这是protobuf的另一种实现,与原始协议兼容。
当您将要填充的缓冲区传递给它时,可以通过多个封送调用重复使用同一缓冲区。显然,缓冲区应该足够大。
func MarshalTo([]byte, m) error