gob踩坑记录

1.报错gob: duplicate type received

场景: 使用encoder1发送自定义结构体struct1encoder2发送自定义结构体struct2,使用同一个decoder接收这两个结构体。
报错原因: gob在发送自定义结构体时,会先对该类型进行注册。在我们的场景中,encoder1encoder2都向decoder发送注册信息,因此导致类型重复。
解决方法: 对于同一个数据,应使用一一对应的encoderdecoder进行传输。

2.零值被覆盖

场景:

type MyStruct struct {
	id int
	...
}

func handleConn(conn net.Conn) {
	var myStruct MyStruct
	decoder := gob.NewDecoder(conn)
	for {
		decoder.Decode(&myStruct)
	}
}

服务端在一个for循环中使用一个自定义结构体myStruct接收数据,客户端发送三次数据,myStruct.id分别为0,2,0,然而服务端接收到的数据为0,2,2,第三次的零值被覆盖了。
原因: gob传输时会省略零值,而我们是重复向同一个myStruct赋值,因此第二次传输后myStruct.id变为2,第三次传输的零值被省略,看起来就是服务端第三次接收到了2.
解决方法: 两种方法任选其一

  1. id从1开始编码,不使用零值。
  2. 在for循环内部定义myStruct

3.gob读取多余数据

场景: 客户端发送了两个数据ab,服务端使用gob.Decoder接收a,使用net.Conn.Read()接收b,b无法被正确接收。
原因:

// NewDecoder returns a new decoder that reads from the io.Reader.
// If r does not also implement io.ByteReader, it will be wrapped in a
// bufio.Reader.
func NewDecoder(r io.Reader) *Decoder {
	dec := new(Decoder)
	// We use the ability to read bytes as a plausible surrogate for buffering.
	if _, ok := r.(io.ByteReader); !ok {
		r = bufio.NewReader(r)
	}
	dec.r = r
	dec.wireType = make(map[typeId]*wireType)
	dec.decoderCache = make(map[reflect.Type]map[typeId]**decEngine)
	dec.ignorerCache = make(map[typeId]**decEngine)
	dec.countBuf = make([]byte, 9) // counts may be uint64s (unlikely!), require 9 bytes

	return dec
}

在gob源码中,NewDecoder函数会将用户传入的io.Reader包装成io.ByteReaderio.ByteReader会将原io.Reader中的数据全部读取到缓冲区中,后续读取数据时从缓冲区读取指定长度的数据。因此我们的客户端发送的数据b会被存入gob.Decoderio.ByteReader的缓冲区中,无法再被其他函数读取。

解决方法: 在设计传输协议时,保证在使用gob传输阶段,不会传输多余数据。举个栗子,在上面的场景中,客户端向服务端发送a后,先等待从服务端接收c后,再向服务端发送b

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值