1.报错gob: duplicate type received
场景: 使用encoder1
发送自定义结构体struct1
,encoder2
发送自定义结构体struct2
,使用同一个decoder
接收这两个结构体。
报错原因: gob在发送自定义结构体时,会先对该类型进行注册。在我们的场景中,encoder1
和encoder2
都向decoder
发送注册信息,因此导致类型重复。
解决方法: 对于同一个数据,应使用一一对应的encoder
和decoder
进行传输。
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.
解决方法: 两种方法任选其一
- id从1开始编码,不使用零值。
- 在for循环内部定义
myStruct
。
3.gob读取多余数据
场景: 客户端发送了两个数据a
和b
,服务端使用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.ByteReader
,io.ByteReader
会将原io.Reader
中的数据全部读取到缓冲区中,后续读取数据时从缓冲区读取指定长度的数据。因此我们的客户端发送的数据b
会被存入gob.Decoder
的io.ByteReader
的缓冲区中,无法再被其他函数读取。
解决方法: 在设计传输协议时,保证在使用gob传输阶段,不会传输多余数据。举个栗子,在上面的场景中,客户端向服务端发送a
后,先等待从服务端接收c
后,再向服务端发送b
。