转载

Thrift的TJsonProtocol协议分析

Thrift协议实现目前有二进制协议(TBinaryProtocol),紧凑型二进制协议(TCompactProtocol)和Json协议(TJsonProtocol)。

前面的两篇文字从编码和协议原理方面分析了TBinaryProtocol和TCompactProtocol协议,下面对TJsonProtocol协议做一下分析。

TJsonProtocol协议相对比较简单,在网络中以文本方式传输,易于转包分析和理解。

1. 数据类型表示方式和简写

数据类型
数据类型 Json协议节点简写 C++表示方式 Go表示方式 Java表示方式 Lua表示方式
布尔 tf bool bool boolean true/false
字节/8位 i8 int8_t,char int8 byte
16位整数 i16 int16_t int16 short
32位整数 i32 int32_t int32 int
64位整数 i64 int64_t int64 long
双精度小数 dbl double float64 double
字符串 str string string String
结构体 rec struct struct class table
列表 lst std:list<value> []type List<ValueType> table[value] = bool
集合 set std:set<value> map[ValueType]bool Set<ValueType> table[value] = bool
字典/映射 map std:map<key, value> map[KeyType]ValueType Map<KeyType,ValueType> table[key] = value

2.各数据类型表示方式

Thrift的TJsonProtocol协议分析

bool,i8,i16,i32,i64,double,string的Json表示格式:

"编号": {   "类型": "值" },

结构体Json表示格式:

"编号": {   "rec": {     "成员编号": {       "成员类型": "成员值"     },     ...   } }

Map的Json表示格式:

"编号": {   "map": ["键类型",     "值类型",     元素个数,     {       "键1": "值1",       "键n": "值n"     }    ] },

Set和List的Json表示方式:

"编号": {   "set/lst": ["值类型",     元素个数,     "ele1",     "ele2",     "elen"   ] },

3. 编写Thrift的IDL文件并生成Golang代码

thrift --gen  go rpc.thrift

namespace go demo.rpc namespace cpp demo.rpc namespace java demo.rpc  struct ArgStruct {     1:byte argByte,     2:string argString     3:i16  argI16,     4:i32  argI32,     5:i64  argI64,     6:double argDouble,     7:bool   argBool, }  service RpcService {     list<string> funCall(         1:ArgStruct argStruct,         2:byte argByte,         3:i16  argI16,         4:i32  argI32,         5:i64  argI64,         6:double argDouble,         7:string argString,         8:map<string, string> paramMapStrStr,         9:map<i32, string> paramMapI32Str,         10:set<string> paramSetStr,         11:set<i64> paramSetI64,         12:list<string> paramListStr,         13:bool   argBool,         ), }

编写客户端测试代码

package main   import (     "demo/rpc"     "fmt"     "git.apache.org/thrift.git/lib/go/thrift"     "net"     "os"     "time" )   func main() {     startTime := currentTimeMillis()     transportFactory := thrift.NewTTransportFactory()     protocolFactory := thrift.NewTJSONProtocolFactory()       transport, err := thrift.NewTSocket(net.JoinHostPort("10.10.36.143", "8090"))     if err != nil {         fmt.Fprintln(os.Stderr, "error resolving address:", err)         os.Exit(1)     }       useTransport := transportFactory.GetTransport(transport)     client := rpc.NewRpcServiceClientFactory(useTransport, protocolFactory)     if err := transport.Open(); err != nil {         fmt.Fprintln(os.Stderr, "Error opening socket to 127.0.0.1:19090", " ", err)         os.Exit(1)     }     defer transport.Close()       for i := 0; i < 1000; i++ {         argStruct := &rpc.ArgStruct{}         argStruct.ArgByte = 53         argStruct.ArgString = "str value"         argStruct.ArgI16 = 54         argStruct.ArgI32 = 12         argStruct.ArgI64 = 43         argStruct.ArgDouble = 11.22         argStruct.ArgBool = true         paramMap := make(map[string]string)         paramMap["name"] = "namess"         paramMap["pass"] = "vpass"         paramMapI32Str := make(map[int32]string)         paramMapI32Str[10] = "val10"         paramMapI32Str[20] = "val20"         paramSetStr := make(map[string]bool)         paramSetStr["ele1"] = true         paramSetStr["ele2"] = true         paramSetStr["ele3"] = true         paramSetI64 := make(map[int64]bool)         paramSetI64[11] = true         paramSetI64[22] = true         paramSetI64[33] = true         paramListStr := []string{"l1.","l2."}         r1, e1 := client.FunCall(argStruct,             53, 54, 12, 34, 11.22, "login", paramMap,paramMapI32Str,             paramSetStr, paramSetI64, paramListStr, false)         fmt.Println(i, "Call->", r1, e1)         break     }       endTime := currentTimeMillis()     fmt.Println("Program exit. time->", endTime, startTime, (endTime - startTime)) }   // 转换成毫秒 func currentTimeMillis() int64 {     return time.Now().UnixNano() / 1000000 }

使用NewTJSONProtocolFactory方法使用Json协议。

编写服务段测试代码

package main   import (     "demo/rpc"     "fmt"     "git.apache.org/thrift.git/lib/go/thrift"     "os" )   const (     NetworkAddr = ":8090" )   type RpcServiceImpl struct { }   func (this *RpcServiceImpl) FunCall(argStruct *rpc.ArgStruct,     argByte int8, argI16 int16, argI32 int32,     argI64 int64, argDouble float64, argString string,     paramMapStrStr map[string]string, paramMapI32Str map[int32]string,     paramSetStr map[string]bool, paramSetI64 map[int64]bool,     paramListStr []string, argBool bool) (r []string, err error) {     fmt.Println("-->FunCall:", argStruct)     r = append(r, "return 1 by FunCall.")     r = append(r, "return 2 by FunCall.")     return }   func main() {     transportFactory := thrift.NewTTransportFactory()     protocolFactory := thrift.NewTJSONProtocolFactory()       serverTransport, err := thrift.NewTServerSocket(NetworkAddr)     if err != nil {         fmt.Println("Error!", err)         os.Exit(1)     }       handler := &RpcServiceImpl{}     processor := rpc.NewRpcServiceProcessor(handler)       server := thrift.NewTSimpleServer4(processor, serverTransport,transportFactory, protocolFactory)     fmt.Println("thrift server in", NetworkAddr)     server.Serve() }

使用NewTJSONProtocolFactory方法使用Json协议。

测试前抓包分析

请求报文:

[     1,     "funCall",     1,     1,     {         "1": {             "rec": {                 "1": {                     "i8": 53                 },                 "2": {                     "str": "str value"                 },                 "3": {                     "i16": 54                 },                 "4": {                     "i32": 12                 },                 "5": {                     "i64": 43                 },                 "6": {                     "dbl": 11.22                 },                 "7": {                     "tf": 1                 }             }         },         "2": {             "i8": 53         },         "3": {             "i16": 54         },         "4": {             "i32": 12         },         "5": {             "i64": 34         },         "6": {             "dbl": 11.22         },         "7": {             "str": "login"         },         "8": {             "map": [                 "str",                 "str",                 2,                 {                     "name": "namess",                     "pass": "vpass"                 }             ]         },         "9": {             "map": [                 "i32",                 "str",                 2,                 {                     "10": "val10",                     "20": "val20"                 }             ]         },         "10": {             "set": [                 "str",                 3,                 "ele1",                 "ele2",                 "ele3"             ]         },         "11": {             "set": [                 "i64",                 3,                 11,                 22,                 33             ]         },         "12": {             "lst": [                 "str",                 2,                 "l1.",                 "l2."             ]         },         "13": {             "tf": 0         }     } ]

请求报文分析:

一条消息用中括号 [] 括起来。

第1个元素1 表示协议版本,目前TJsonProtocol协议版本为1。

第2个元素funCall 表示消息的名称。

第3个元素1 表示消息请求,(消息请求:1,消息响应:2,消息异常:3,oneway消息:4)。

第4个元素1 表示消息流水号。

一条消息的参数用大括号{} 括起来。

消息参数的node键名称为thrift文件中定义的字段编号,node值由值类型和值组成。

如:

"1": {     "i8": 53 },

1 表示字段编号,i8表示值类型为8位整数或一个字节,53表示值。

其他也是同样的含义,不再赘述。

响应报文:

[     1,     "funCall",     2,     1,     {         "0": {             "lst": [                 "str",                 2,                 "return 1 by FunCall.",                 "return 2 by FunCall."             ]         }     } ]

响应报文分析:

一条消息用中括号 [] 括起来。

第1个元素1 表示协议版本,目前TJsonProtocol协议版本为1。

第2个元素funCall 表示消息的名称。

第3个元素2 表示消息响应,(消息请求:1,消息响应:2,消息异常:3,oneway消息:4)。

第4个元素1 表示消息流水号。

接下来的字段是返回的参数。

Done.

原文  http://www.cnblogs.com/voipman/p/5175169.html
正文到此结束
Loading...