2015-07-21 51 views
0

我正在寻找干净的方式将字节数组转换为客户机 - 服务器应用程序的结构体。 我知道大多数ppl转向采用这种解决方案的gob包,但是我不控制应用程序的编码。这就是说,我只编写服务器应用程序而不是客户端,有一个正在交换的协议的相互协议。golang将字节数组转换为结构体

我可以出来的最好的是以下。

type T struct { 
    A int16 
    B int8 
    C []byte 
} 

func main() { 
    // Create a struct and write it. 
    t := T{A: 99, B: 10} 
    buf := &bytes.Buffer{} 

    buf1 := []byte{5, 100, 100} 
    fmt.Println(buf1) 

    buf.Write(buf1) 

    //err := binary.Write(buf, binary.BigEndian, t) 

    //if err != nil { 
    // panic(err) 
    //} 
    fmt.Println(buf) 

    // Read into an empty struct. 
    t = T{} 
    err := binary.Read(buf, binary.BigEndian, &t) 
    if err != nil { 
     panic(err) 
    } 
    fmt.Printf("%d %d", t.A, t.B) 
} 

但是,只要数字字节与结构的大小不一致,那么就会发出恐慌。我怎么能修改此无需恐慌工作,如果过小或过大的

Go playground

+0

你只是控制服务器端,意味着你已经有串行协议。你有什么协议,是你问题的关键。 golang拥有对广泛使用的协议(如JSON,BSON或PROTOBUF)的编码包支持。因此找出串行协议并选择编码包。或者如果您有私人协议,请自行实施编码。 –

+0

这是私人协议。任何示例/文章/ goplayground? – user642318

回答

0

由于您使用的是私有协议。实施自己的协议是个好主意。有很多examplesofhow来做到这一点。

您只受到编码器实现的限制。我建议查看json.Decoder来处理缓冲区,而不是看直接的字节片。这些操作在缓冲区上,对于大数据流非常有用。

+0

私有协议实际上不是以文本的形式(如json),而是在逻辑上以字节表示。事实上,在一些切片中,比特在这些协议中被表示为标志。任何指导哪里会是一个更好的例子? – user642318

1

根据http://golang.org/pkg/encoding/binary/#Read

数据必须指向一个固定大小的值或一片固定大小值。

所以你不能在你的结构采用分片[]byte。但是你可以使用固定大小的数组。
像这样:Go playground

+0

任何想法如何转换为可变大小 – user642318

+0

取决于您的数据结构。你可以将源数组分成两部分。第一部分将只包含固定大小的数据(在你的情况下为3字节的A和B)。第二部分将包含数组数据。用这种方法,你需要创建新的结构,而不需要数组部分,就像'类型T结构'int16 \t B int8 }'。并分别解码这两个部分 – RoninDev

0

我认为binpacker将是马丽娟来处理这种情况:

package main 

import (
    "bytes" 
    "fmt" 

    "github.com/zhuangsirui/binpacker" 
) 

type T struct { 
    A uint16 
    B string 
    C []byte 
} 

func main() { 
    field1 := uint16(1) 
    field2 := "Hello World" 
    field3 := []byte("Hello World") 
    buffer := new(bytes.Buffer) 
    binpacker.NewPacker(buffer). 
     PushUint16(field1). 
     PushUint16(uint16(len(field2))).PushString(field2). 
     PushUint16(uint16(len(field3))).PushBytes(field3) 

    t := new(T) 
    unpacker := binpacker.NewUnpacker(buffer) 
    unpacker.FetchUint16(&t.A).StringWithUint16Perfix(&t.B).BytesWithUint16Perfix(&t.C) 
    fmt.Println(t) 
}