binary与bytes包配合使用
1.bytes.Reader
bytes.Reader是一个实现了io.Reader接口的结构体,用于方便从指定的切片中读取数据。
可以从一个已有的切片构造bytes.Reader,方便读写切片。
构造:
func NewReader(b []byte) *Reader
操作:
func (r *Reader) Read(b []byte) (n int, err error)
Reader从底层切片中到目标切片b中,读取数量为b的大小,如果不够读取源切片全部数据,返回读取到的字节数量。
2.bytes.Buffer
该接口是实现了io.Reader和io.Writer接口的字节缓。
构造:
//方法1:根据指定的切片构造Buffer
func NewBuffer(buf []byte) *Buffer
//方法2:直接构造空Buffer
buf := new(bytes.Buffer)
使用:
//从buffer中读取len(p)大小的数据
func (b *Buffer) Read(p []byte) (n int, err error)
//往buffer中写入p切片中的数据
func (b *Buffer) Write(p []byte) (n int, err error)
3.binary.Read
从r中读取binary编码的数据并赋给data,data必须是一个指向定长值的指针或者定长值的切片。
原型:
func Read(r io.Reader, order ByteOrder, data interface{}) error
参数1:实现io.Reader接口的结构
参数2:大小端字节序
参数3:要从r中读取到的二进制数据保存到data变量中
如果有错误返回error
使用:
bytes.Reader结构实现了io.Reader接口,所以可以使用binary.Read从bytes.Reader中读取二进制切片数据到指定data变量中。
var pi float64
b := []byte{0x18, 0x2d, 0x44, 0x54, 0xfb, 0x21, 0x09, 0x40}
Reader := bytes.NewReader(b)
err := binary.Read(Reader, binary.LittleEndian, &pi)
if err != nil {
fmt.Println("binary.Read failed:", err)
}
fmt.Print(pi)
4.binary.Write
把data数据按照指定的字节序写到w中,w是实现了io.Writer接口的类型。
原型:
func Write(w io.Writer, order ByteOrder, data interface{}) error
参数1:w是实现了io.Writer接口类型的数据。
参数2:大小端字节序
参数3: 把data变量中的二进制数据写到w中。
使用:
bytes.Buffer结构实现了io.Reader,io.Writer接口,所以可以使用binary.Write()将data变量的数据,写入到buffer中。
buf := new(bytes.Buffer)
var pi float64 = math.Pi
err := binary.Write(buf, binary.LittleEndian, pi)
//将pi写入到buffer中
if err != nil {
fmt.Println("binary.Write failed:", err)
}
fmt.Printf("% x", buf.Bytes())
example
//server
package main
import (
"bytes"
"encoding/binary"
"fmt"
"log"
"net"
"unsafe"
)
func init() {
log.SetFlags(log.Lshortfile)
}
type MessageHeader struct {
MessageType int32
MessageLength int32
}
func Handle(conn net.Conn) {
//处理连接的读写
message_header := MessageHeader{}
//go语言的sizeof参数是实例出的对象的大小,不能传类型,跟C++不同
bin_data := make([]byte, unsafe.Sizeof(message_header))
_, err := conn.Read(bin_data)
if err != nil {
log.Println("conn.Read,error", err)
return
}
//创建一个基于bin_data的Bytes.Reader
reader := bytes.NewReader(bin_data)
//把读到的数据写入header中
err = binary.Read(reader, binary.LittleEndian, &message_header)
if err != nil {
log.Println("binary.Read error = ", err)
return
}
fmt.Println(message_header)
conn.Write(bin_data)
}
func main() {
listenner, err := net.Listen("tcp", "127.0.0.1:9000")
if err != nil {
log.Fatalln("net.Listen error:=", err)
}
for {
conn, err := listenner.Accept()
if err != nil {
log.Println("listenner.Accept() error:=", err)
continue
}
go Handle(conn)
}
}
//client
package main
import (
"bytes"
"encoding/binary"
"fmt"
"log"
"net"
"time"
"unsafe"
)
type MessageHeader struct {
MessageType int32 //这里有个坑,请不要定义int类型,否则binary解析会有问题,因为int大小根据平台而定,不是定长的
MessageLength int32
}
func init() {
log.SetFlags(log.Lshortfile)
}
func main() {
conn, err := net.Dial("tcp", "127.0.0.1:9000")
if err != nil {
log.Panicln("net.Dial errr,", err)
}
buffer := new(bytes.Buffer)
header := &MessageHeader{
MessageType: 1,
MessageLength: 20,
}
err = binary.Write(buffer, binary.LittleEndian, header)
if err != nil {
log.Println("binary.Write err,", err)
return
}
_, err = conn.Write(buffer.Bytes())
if err != nil {
log.Println("conn.Wirte err,", err)
return
}
bin_data := make([]byte, unsafe.Sizeof(header))
conn.Read(bin_data)
target := &MessageHeader{}
reader := bytes.NewReader(bin_data)
binary.Read(reader, binary.LittleEndian, target)
fmt.Println(target)
time.Sleep(time.Second * 5)
}