binary與bytes包配合使用
1.bytes.Reader
bytes.Reader是一個實現(xiàn)了io.Reader接口的結(jié)構(gòu)體,用于方便從指定的切片中讀取數(shù)據(jù)吠卷。
可以從一個已有的切片構(gòu)造bytes.Reader,方便讀寫切片个唧。
構(gòu)造:
func NewReader(b []byte) *Reader
操作:
func (r *Reader) Read(b []byte) (n int, err error)
Reader從底層切片中到目標(biāo)切片b中钥顽,讀取數(shù)量為b的大小坟冲,如果不夠讀取源切片全部數(shù)據(jù)睛挚,返回讀取到的字節(jié)數(shù)量邪蛔。
2.bytes.Buffer
該接口是實現(xiàn)了io.Reader和io.Writer接口的字節(jié)緩。
構(gòu)造:
//方法1:根據(jù)指定的切片構(gòu)造Buffer
func NewBuffer(buf []byte) *Buffer
//方法2:直接構(gòu)造空Buffer
buf := new(bytes.Buffer)
使用:
//從buffer中讀取len(p)大小的數(shù)據(jù)
func (b *Buffer) Read(p []byte) (n int, err error)
//往buffer中寫入p切片中的數(shù)據(jù)
func (b *Buffer) Write(p []byte) (n int, err error)
3.binary.Read
從r中讀取binary編碼的數(shù)據(jù)并賦給data扎狱,data必須是一個指向定長值的指針或者定長值的切片侧到。
原型:
func Read(r io.Reader, order ByteOrder, data interface{}) error
參數(shù)1:實現(xiàn)io.Reader接口的結(jié)構(gòu)
參數(shù)2:大小端字節(jié)序
參數(shù)3:要從r中讀取到的二進制數(shù)據(jù)保存到data變量中
如果有錯誤返回error
使用:
bytes.Reader結(jié)構(gòu)實現(xiàn)了io.Reader接口勃教,所以可以使用binary.Read從bytes.Reader中讀取二進制切片數(shù)據(jù)到指定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數(shù)據(jù)按照指定的字節(jié)序?qū)懙絯中匠抗,w是實現(xiàn)了io.Writer接口的類型故源。
原型:
func Write(w io.Writer, order ByteOrder, data interface{}) error
參數(shù)1:w是實現(xiàn)了io.Writer接口類型的數(shù)據(jù)。
參數(shù)2:大小端字節(jié)序
參數(shù)3: 把data變量中的二進制數(shù)據(jù)寫到w中汞贸。
使用:
bytes.Buffer結(jié)構(gòu)實現(xiàn)了io.Reader,io.Writer接口绳军,所以可以使用binary.Write()將data變量的數(shù)據(jù),寫入到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參數(shù)是實例出的對象的大小门驾,不能傳類型,跟C++不同
bin_data := make([]byte, unsafe.Sizeof(message_header))
_, err := conn.Read(bin_data)
if err != nil {
log.Println("conn.Read,error", err)
return
}
//創(chuàng)建一個基于bin_data的Bytes.Reader
reader := bytes.NewReader(bin_data)
//把讀到的數(shù)據(jù)寫入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大小根據(jù)平臺而定竣灌,不是定長的
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)
}