🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
[TOC] ## binary.Size 获取结构体的大小 固定大小的结构体,就要求结构体中不能出现\[\]byte这样的切片成员,否则Size返回-1,且不能进行正常的序列化操作 code ``` a0 := 123 // or a0 := "123" fmt.Printf("a0 : %d \n", binary.Size(a0)) // -1 a1 := int16(123) fmt.Printf("a1 : %d \n", binary.Size(a1)) // 2 a2 := uint16(123) fmt.Printf("a2 : %d \n", binary.Size(a2)) // 2 a3 := uint32(123) fmt.Printf("a3 : %d \n", binary.Size(a3)) // 4 a4 := uint64(123) fmt.Printf("a4 : %d \n", binary.Size(a4)) // 8 type b struct { b1 uint16 b2 uint32 } var B b fmt.Printf("B : %d \n", binary.Size(B)) //6 B.b1 = uint16(32) fmt.Printf("B : %d \n", binary.Size(B)) //6 ``` ## 小端序与大端序 序列化 1. 网络的数据是以大端数据模式进行交互 2. 主机大多数以小端模式处理,如果不转换,数据会混乱 数值`0x2211`使用两个字节储存:高位字节是`0x22`,低位字节是`0x11`,**并不是数值的大小** * **大端字节序**:高位字节在前,低位字节在后,这是人类读写数值的方法。 * **小端字节序**:低位字节在前,高位字节在后,即以`0x1122`形式储存。 ``` a :=int32(65535) buf :=new(bytes.Buffer) binary.Write(buf,binary.LittleEndian,a) fmt.Printf("%+v\n", buf.Bytes()) // [255 255 0 0] buf2 :=new(bytes.Buffer) binary.Write(buf2,binary.BigEndian,a) fmt.Printf("%+v\n", buf2.Bytes()) // [0 0 255 255] ``` > 结构体也可同理实现小端序,大端序的序列化 ### 结构体转为序列化 ``` type A struct { One int32 Two int32 } var a A a.One = int32(1) a.Two = int32(3) fmt.Println("a's size is ", binary.Size(a)) // 8 buf := new(bytes.Buffer) binary.Write(buf, binary.LittleEndian, a) fmt.Println("after write ,buf is:", buf.Bytes()) //[1 0 0 0 3 0 0 0] ``` 1. 这里采用了小端序的方式进行序列化(x86架构都是小端序,网络字节序是大端序) 2. 对于结构体中得“_”成员不进行序列化 3. 结构体中不能出现\[\]byte这样的切片成员,否则Size返回-1 ### 序列化(buffer)转结构体 ``` type A struct { One uint16 Two int32 } var aa A aa.One=65535 var bb A buf := new(bytes.Buffer) binary.Write(buf,binary.LittleEndian,aa) //序列化 binary.Read(buf,binary.LittleEndian,&bb) //反序列化 fmt.Printf("%+v\n", bb) //{One:65535 Two:0} ``` > 只有多于一位的才需要指定大端序 ### 编码字节切片 ``` // write v := uint32(500) buf := make([]byte,4) //需大于4位, 过小 抛出异常 index out of range [3] with length 3 binary.BigEndian.PutUint32(buf, v) // read x := binary.BigEndian.Uint32(buf) fmt.Printf("%+v\n", x) ``` ### 流处理 读写固定长度值的流 (stream) Read 通过指定类型的字节序把字节解码 (decode) 到 data 变量中。解码布尔类型时,0 字节 (也就是 `[]byte{0x00}` ) 为 false, 其他都为 true Read ``` func main() { var( piVar float64 boolVar bool ) piByte := []byte{0x18, 0x2d, 0x44, 0x54, 0xfb, 0x21, 0x09, 0x40} boolByte := []byte{0x00} piBuffer := bytes.NewReader(piByte) boolBuffer := bytes.NewReader(boolByte) binary.Read(piBuffer, binary.LittleEndian, &piVar) binary.Read(boolBuffer, binary.LittleEndian, & boolVar) fmt.Println("pi", piVar) // pi 3.141592653589793 fmt.Println("bool", boolVar) // bool false } ``` Write ``` func main() { buf := new(bytes.Buffer) var pi float64 = math.Pi err := binary.Write(buf, binary.LittleEndian, pi) if err != nil { fmt.Println("binary.Write failed:", err) } fmt.Printf("% x", buf.Bytes()) // 18 2d 44 54 fb 21 09 40 } ``` 在实际编码中,面对复杂的数据结构,可考虑使用更标准化高效的协议,比如[google-Protocol Buffer](https://developers.google.com/protocol-buffers/) ### 包头定义的例子 ``` // 定义协议 type Pack struct { Length uint32 // 长度 4个字节 Order uint32 // 序号 SecretKey1 byte // 随机秘钥1 SecretKey2 byte // 随机秘钥2 Cmd constant.CmdCode // cmd 命令 如 0x0008=为登录 0x0008=登出 StaticCode constant.StaticCode // 状态 0-正常 1-出错 2-命令未完成 0x000 3-命令需要ack Encryption constant.EncrCode // 加密: 0-误操作 1-AES256 2-国产sm4 Reserv uint16 // 随机值 Body []byte // body Ext Ext } // Pack 的值赋值给 writer func (p *Pack) Pack(writer io.Writer) error { var err error err = binary.Write(writer, binary.BigEndian, &p.Length) err = binary.Write(writer, binary.BigEndian, &p.Order) err = binary.Write(writer, binary.BigEndian, &p.SecretKey1) err = binary.Write(writer, binary.BigEndian, &p.SecretKey2) err = binary.Write(writer, binary.BigEndian, &p.Cmd) err = binary.Write(writer, binary.BigEndian, &p.StaticCode) err = binary.Write(writer, binary.BigEndian, &p.Encryption) err = binary.Write(writer, binary.BigEndian, &p.Reserv) err = binary.Write(writer, binary.BigEndian, &p.Body) return err } // pack的值复制给 reader func (p *Pack) UnPack(b []byte) error { reader := bytes.NewReader(b) var err error err = binary.Read(reader, binary.BigEndian, &p.Length) err = binary.Read(reader, binary.BigEndian, &p.Order) err = binary.Read(reader, binary.BigEndian, &p.SecretKey1) err = binary.Read(reader, binary.BigEndian, &p.SecretKey2) err = binary.Read(reader, binary.BigEndian, &p.Cmd) err = binary.Read(reader, binary.BigEndian, &p.StaticCode) err = binary.Read(reader, binary.BigEndian, &p.Encryption) err = binary.Read(reader, binary.BigEndian, &p.Reserv) p.Body = make([]byte, p.Length-HAND_BODY) err = binary.Read(reader, binary.BigEndian, &p.Body) return err } ```