问题描述:
有一个结构体作为rpc传输用的结构体:
type RpcDataArgs struct {
Typ string
Time string
DJV interface{}
Action string //tuple_info 是否阻断
}
其中DJV
是interface{}
,实例化一个结构体:
rpcargs := RpcDataArgs{Typ: typ, DJV: osinfo} //osinfo是一个结构体
rpcCall(rpcargs)
传输之后服务端处理:
func process(args *RpcDataArgs) error {
d := args.DJV
c:=reflect.TypeOf(d).String()
osinfo, ok := d.(OsInfo) //本来计划进行正常的类型转化
fmt.Println(c,ok)
}
打印结果为:map[string]interface {},false
***问题:***传入的是一个结构体,怎么拿到的成了map
寻因
查看rpc官方文档的编解码部分:https://doc.rpcx.io/part3/codec.html
在没有自己选择的情况下,官方默认的编解码是MsgPack
编码器问题:会把interface{}转换成map[string]interface{},原因暂未知,可能是由这个编码器为了跨语言而做的处理(interface{}是golang独有的,而map是所有语言通用的)
致命问题:把struct 转换成map[string]interface {}后,要使用mao中元素,还需要再转。直接用会报错。
package main
import "fmt"
import "reflect"
import "github.com/vmihailenco/msgpack"
func ExampleMarshal() {
type FFFFF struct {
Name string
Age int
QQ []int
AAA map[int]int
}
pp := FFFFF{
Name: "fsdf",
Age: 14,
QQ: []int{2, 1},
// AAA: map[int]int{
// 1: 3,
// },
}
type Item struct {
Foo string
TTT int
HHH float64
KKK map[string]int
NNN []int
MMM interface{}
}
b, err := msgpack.Marshal(&Item{MMM: pp, Foo: "bar", TTT: 76, HHH: 78.1, KKK: map[string]int{"Fds": 23}, NNN: []int{2, 3, 2}})
if err != nil {
panic(err)
}
var item Item
err = msgpack.Unmarshal(b, &item)
if err != nil {
panic(err)
}
fmt.Println(reflect.TypeOf(item.MMM).String())
// fmt.Println(reflect.TypeOf(item.MMM.Name).String())
// fmt.Println(reflect.TypeOf(item.MMM.QQ).String())
// fmt.Println(reflect.TypeOf(item.MMM.Age).String())
fmt.Println(item.Foo)
fmt.Println(reflect.TypeOf(item.Foo).String())
fmt.Println(item.TTT)
fmt.Println(reflect.TypeOf(item.TTT).String())
fmt.Println(item.HHH)
fmt.Println(reflect.TypeOf(item.HHH).String())
fmt.Println(item.KKK)
fmt.Println(reflect.TypeOf(item.KKK).String())
fmt.Println(item.NNN)
fmt.Println(reflect.TypeOf(item.NNN).String())
}
func main() {
ExampleMarshal()
}
结论:
该问题暂未解决,自己选择别的编码器也是一样的结果。
无法做到任意兼容性
暂时的解决方法:
传入的数据类型是确定的结构体类型或者是map[string]interface {}等
即
type RpcDataArgs struct {
Typ string
Time string
DJV osinfo //osinfo是结构体类型
Action string //tuple_info 是否阻断
}
或者:
type RpcDataArgs struct {
Typ string
Time string
DJV map[string]interface {} //比较麻烦,服务端还需要转换类型
Action string //tuple_info 是否阻断
}
拓展
(如何自己选择编码器)
要在客户端进行设置(注释部分):
import (
//"github.com/smallnest/rpcx/protocol"
)
func datainit(){
d := client.NewPeer2PeerDiscovery("tcp@" + *addr, "")
opt := client.DefaultOption
opt.ConnectTimeout = RPCConnTimeout
//opt.SerializeType = protocol.JSON //选择编码器,默认msgpack
xclient = client.NewXClient("Arith", client.Failfast, client.RandomSelect, d, opt)
}
rpcx提供的可选择编码器(编码器具体内容可参考文档)
const (
// SerializeNone uses raw []byte and don't serialize/deserialize
SerializeNone SerializeType = iota
// JSON for payload.
JSON
// ProtoBuffer for payload.
ProtoBuffer
// MsgPack for payload
MsgPack
// Thrift
// Thrift for payload
Thrift
)