Thrift協議實現目前有二進制協議(TBinaryProtocol),緊湊型二進制協議(TCompactProtocol)和Json協議(TJsonProtocol)。javascript
前面的兩篇文字從編碼和協議原理方面分析了TBinaryProtocol和TCompactProtocol協議,下面對TJsonProtocol協議作一下分析。java
TJsonProtocol協議相對比較簡單,在網絡中以文本方式傳輸,易於抓包分析和理解。node
1. 數據類型表示方式和簡寫git
數據類型 | 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.各數據類型表示方式apache
bool,i8,i16,i32,i64,double,string的Json表示格式:網絡
"編號": { "類型": "值" },
結構體Json表示格式:app
"編號": { "rec": { "成員編號": { "成員類型": "成員值" }, ... } }
Map的Json表示格式:socket
"編號": { "map": ["鍵類型", "值類型", 元素個數, { "鍵1": "值1", "鍵n": "值n" } ] },
Set和List的Json表示方式:測試
"編號": { "set/lst": ["值類型", 元素個數, "ele1", "ele2", "elen" ] },
3. 編寫Thrift的IDL文件並生成Golang代碼this
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.