golang的gob是干嘛的?首先我们有一串数据,我们想让这些数据序列化,但是怎么序列化,序列化的格式是什么?我们都可以通过encoder去定义,比如我们想让一大坨数据(比如非常复杂的结构)序列化成json
格式,或者序列化成array
等等,我们如何序列化呢?我们使用encoding/gob
这个包进行序列化
先贴上官网的简介
Package gob manages streams of gobs - binary values exchanged between an Encoder (transmitter) and a Decoder (receiver). A typical use is transporting arguments and results of remote procedure calls (RPCs) such as those provided by package “net/rpc”.
我们大概了解到gob是一个管理流的工具,用于encode数据成为二进制数据,然后传给decoder,叫decoder解码成原始数据,这样做的好处是什么?我们之前说到encode可以encode成为json等数据,但是我们的gob是encode成二进制数据,其实我们传输数据的时候如果中间被抓包,对方解包一看就可以看到数据明文,加入我们encode后在传输的过程中就是二进制文件,攻击者无法直接读我的数据
gob的接收端和发送端不需要数据完全一致,完全对应
我们在使用gob的时候会传入bytes.buffer
类型,什么是bytes.buffer
?为什么我们需要她?直接上数组[]bytes
不好吗?
其实本质上
bytes.buffer
就是[]bytes
加上一些方法和其他的组件,比如你可以read,write,那么为什么encode要传入这个东西呢?因为他在encode的场景下做为一个缓存的存在,encode有什么失败的都是先存入bytes.buffer
中,因为bytes.buffer
的底层是[]byte
实现的,所以其可以自动扩容,当空间不够的时候,扩容会导致copy,和c++ vector自动扩容有点像,都是当写入bytes.buffer
的时候发现内存不够,然后新开辟一个内存,然后将原有bytes.buffer
和新写入的数据都写入这段新开辟的内存,然后再销毁之前的内存,c++ vector的copy可能会导致拷贝构造具体看这里
普通的编码和解码代码1如下,
package main
import (
"bytes"
"encoding/gob" //gob
"fmt"
)
type MsgData struct {
X, Y, Z int
Name string
}
var network bytes.Buffer
func main() {
err := senMsg()
if err != nil {
fmt.Println("编码错误")
return
}
err = revMsg()
if err != nil {
fmt.Println("解码错误")
return
}
}
func senMsg() error {
fmt.Print("开始执行编码(发送端)")
enc := gob.NewEncoder(&network) //新建编码器
sendMsg := MsgData{3, 4, 5, "jiangzhou"}
fmt.Println("原始数据:", sendMsg)
err := enc.Encode(&sendMsg) //编码器开始编码
fmt.Println("编码后的数据为: ", network)
return err
}
func revMsg() error {
var revData MsgData
dec := gob.NewDecoder(&network) //新建解码器
err := dec.Decode(&revData) //开始解码,解码后存入这个struct数据结构中
fmt.Println("解码之后的数据为: ", revData)
return err
}
decode返回不为nil
说明错误,假设decode传入一个nil,说明对饮的值会被放弃。
我们也可以在一个bytes.Buffer
中传入多个要encode的节点,然后一个一个解码赋值
package main
import (
"bytes"
"encoding/gob"
"fmt"
)
type message struct {
a1 int
a2 int
c1 string
}
func main() {
transmes := message{a1: 1,
a2: 2,
c1: "abc",
}
var recivemes message
w := new(bytes.Buffer)
e := gob.NewEncoder(w)
e.Encode(transmes.a1)
e.Encode(transmes.a2)
fmt.Println("w after encode is ", *w)
d := gob.NewDecoder(w)
d.Decode(&recivemes.a1)
d.Decode(&recivemes.a2)
fmt.Println("after decode ", recivemes.a1, recivemes.a2)
}
为什么我们需要register?假如我们处理一些具体结构比如struct的时候我们可以忽略register,但是当我们处理interface的时候我们必须要先register我们interface里面的类型,例如我们有一个struct和interface想编码,看下面程序2
package main
import (
"bytes"
"encoding/gob"
"fmt"
)
type Getter interface {
Get() string
}
type Foo struct {
Bar string
}
func (f Foo) Get() string {
return f.Bar
}
func main() {
buf := bytes.NewBuffer(nil) //创建一个缓冲区,且用空去初始化他,如果这个nil换成其他的buffer就相当于用传入的buffer赋值给新的buffer
gob.Register(Foo{}) //注册Foo结构因为我们要编码interface
//create a interface getter of Foo
g := Getter(Foo{"zhr"})
//encode interface getter
enc := gob.NewEncoder(buf)
enc.Encode(&g)
fmt.Println("after encode is ", buf)
//decode
dec := gob.NewDecoder(buf)
var gg Getter
if err := dec.Decode(&gg); err != nil {
panic(err)
}
fmt.Println("after decode is ", gg)
}
为什么我们在encode一个interface的时候必须要注册?因为假如我们不注册interface里的struct,gob在decode的时候不知道如何将interface map回适当的类型