zoukankan      html  css  js  c++  java
  • 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.各数据类型表示方式

    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.

  • 相关阅读:
    MS SQLSERVER 第三天
    MS SQLSERVER 第二天
    今天开始我的 MSSQLSERVER 之旅
    从今天开始就正式我的博客之旅
    mac 本地搭建mybatisGenerator代码生成环境
    idea中git远程版本回退
    Junit调试解决本地多线程异步调用
    Lambda表达式总结
    JDK8函数式编程之Stream API
    MySql分页查询慢的解决方案
  • 原文地址:https://www.cnblogs.com/voipman/p/5175169.html
Copyright © 2011-2022 走看看