当前位置: 首页 > 工具软件 > GOB > 使用案例 >

golang gob

曾嘉荣
2023-12-01

前言

golang的gob是干嘛的?首先我们有一串数据,我们想让这些数据序列化,但是怎么序列化,序列化的格式是什么?我们都可以通过encoder去定义,比如我们想让一大坨数据(比如非常复杂的结构)序列化成json格式,或者序列化成array等等,我们如何序列化呢?我们使用encoding/gob这个包进行序列化

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

为什么我们需要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回适当的类型


  1. 链接1 ↩︎

  2. 链接2 ↩︎

 类似资料:

相关阅读

相关文章

相关问答