序列化结构字段以预存现有的字节片

序列化结构字段以预存现有的字节片

问题描述:

I have a setup where I receive data over the network and serialize it to my struct. It works fine, but now I need to serialize the data to a slice buffer to send it across the network.

I am trying to avoid having to allocate more than needed so I have already set up a buffer which I like to write to for all my serializing. But am not sure how to do this.

My setup is like this:

recieveBuffer := make([]byte, 1500)
header := recieveBuffer[0:1]
message := recieveBuffer[1:]

So I am trying to write fields from a struct to message and the total number of bytes for all the fields as a value for header.

This was how I deserialized to the struct:

// Deserialize ...
func (userSession *UserSession) Deserialize(message []byte) {
    userSession.UID = int64(binary.LittleEndian.Uint32(message[0:4]))
    userSession.UUID = string(message[4:40])
    userSession.Username = string(message[40:])
}

I don't really know how to do the reverse of this, however. Is it possible without creating buffers for each field I want to serialize before copying to message?

我有一个设置,可以通过网络接收数据并将其序列化为我的结构。 它可以正常工作,但是现在我需要将数据序列化到切片缓冲区,以通过网络发送它。 p>

我试图避免分配过多的数据,所以我已经设置了 缓冲区,我想为所有序列化写一个缓冲区。 p>

我的设置如下: p>

  recieveBuffer:= make([] byte,1500  )
header:= recieveBuffer [0:1] 
message:= recieveBuffer [1:] 
  code>  pre> 
 
 

所以我试图将字段从结构体写入 message code>和所有字段的总字节数作为 header code>的值。 p>

这就是我反序列化到struct的方式:

  //反序列化... 
func(userSession * UserSession)反序列化(消息[] byte){
 userSession.UID = int64(binary.LittleEndian.Uint32(message [  0:4])))
 userSession.UUID =字符串(消息[4:40])
 userSession.Username =字符串(消息[40:])
} 
  code>  pre> 
  
 

但是,我真的不知道该怎么做。 p> div>在复制到 message code>之前,是否无需为要序列化的每个字段创建缓冲区?

Given the preallocated buffer buf, you can reverse the process like this:

buf[0] = byte(40+len(userSession.Username))
binary.LittleEndian.PutUint32(buf[1:], uint32(int32(userSession.UID)))
copy(buf[5:41], userSession.UUID)
copy(buf[41:], userSession.Username)

Given two helper functions.

One to encode a primitive to a byte slice:

func EncodeNumber2NetworkOrder(v interface{}) ([]byte, error) {
   switch v.(type) {
   case int: // int is at least 32 bits
       b := make([]byte, 4)
       binary.BigEndian.PutUint32(b, uint32(v.(int)))
       return b, nil
   case int8:
       b := []byte{byte(v.(int8))}
       return b, nil
   // ... truncated

and one to convert primitive, non-byte slices to a byte slice

func EncodeBigEndian(in []float64) []byte {
   var out []byte = make([]byte, len(in)*8)
   var wg sync.WaitGroup

   wg.Add(len(in))
   for i := 0; i < len(in); i++ {
       go func(out *[]byte, i int, f float64) {
           defer wg.Done()
           binary.BigEndian.PutUint64((*out)[(i<<3):], math.Float64bits(f))
       }(&out, i, in[i])
   }
   wg.Wait()

   return out
}

your binary serialization might look like this for a bogus struct like

 type Foo struct {
     time int64
     data []float64
 }

 func Encode(f *Foo) []byte {
    da := encoder.EncodeBigEndian(f.data)
    bytes := make([]byte,0)
    bytes = append(bytes, da...)
    return bytes
 }