在lotou中实现了两种二进制编码方式。
binary
一种是普通的C/C++模式的小端编码方式,每一个数据都被依次编码进一个二进制流中,基本用法如下:
- 编码
binary.Encode(v)
binary.Encode(v) - 解码
binary.Decode(&v)
binary.Decode(&v)
使用非常简单,编码方式也很简单。
还有一种是为了用于lotou内部通信(后面即将实现的多节点实现中会用到)
gob
在这种方式中,编码的时候会将数据的类型也编码进二进制流中,这样可以让解码端直接根据二进制流中的类型生成对应的数据,而不是需要根据传入的参数来判断数据需要如何解析。
之所以需要这样做,是因为在服务和服务之间发送数据的时候,发送的实际上是一个[]interface{}的类型,slice的元素的实际类型是未知的,所以必须使编码是类型自描述的。目前该编码方式可以支持除复数外的所有的内置数据类型,以及提前注册进编码中的结构体(所有注册的结构体必须在每一个节点都以相同的顺序注册,因为现在的类型是使用的ID表示,如果注册顺序不一致,会导致解析类型不匹配)。
使用方法也很简单
- 编码
gob.Encode(v1)
gob.Encode(v2) - 解码
v, e := gob.Decode()
v, e := gob.Decode()
要注意decode返回的是一个interface,实际类型在分发到对应服务的时候,由dispatchM函数通过reflect.Value的Call方法自动进行转换。
reflect.Value.Call
func (v Value) Call(in []Value) []Value
这函数中v是一个函数的reflect.Value,in是函数的参数,并且函数的返回值也放在一个Value的slice里面返回。in的每一个元素对应v的一个参数,并且他们必须一一是可赋值的。即in[i]的实际类型是必须是可以赋值给函数的第i个参数的
如果函数的输入有可变参数,那么Call会自动生成可变参数的slice。如果v不是一个func,那么Call函数会panic。