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.

时间: 2024-10-13 05:03:52

Thrift的TJsonProtocol协议分析的相关文章

thrift的TCompactProtocol紧凑型二进制协议分析

Thrift的紧凑型传输协议分析: 用一张图说明一下Thrift的TCompactProtocol中各个数据类型是怎么表示的. 报文格式编码: bool类型: 一个字节. 如果bool型的字段是结构体或消息的成员字段并且有编号,一个字节的高4位表示字段编号,低4位表示bool的值(0001:true, 0010:false),即:一个字节的低4位的值(true:1,false:2). 如果bool型的字段单独存在,一个字节表示值,即:一个字节的值(true:1,false:2). Byte类型:

蓝牙协议分析(7)_BLE连接有关的技术分析

转自:http://www.wowotech.net/bluetooth/ble_connection.html#comments 1. 前言 了解蓝牙的人都知道,在经典蓝牙中,保持连接(Connection)是一个相当消耗资源(power和带宽)的过程.特别是当没有数据传输的时候,所消耗的资源完全被浪费了.因而,对很多蓝牙设备来说(特别是功耗敏感的设备),希望在无数可传的时候,能够断开连接.但是,由于跳频(hopping)以及物理通道(Physical Channel)划分的缘故,经典蓝牙连接

BT协议分析(1)&mdash;1.0协议

简述 BT下载是采用P2P的下载方式,下载的大致形式采用如下图所示,处于图示中心的称为Tracker服务器,其余称为Peer.   缺点 1.资源的安全性 2.资源的实效性(没有上传者则BT也将失效) 3.版权 协议分析 对BT协议(1.0)的分析主要包含4个部分: 1.种子文件的分析 2.同Tracker服务器的通讯(采用HTTP协议) 3.同其他peer(配合/协同者)的通讯(采用TCP协议) 4.总结 分析前的了解 在这些分析之前,需要先了解两点BT协议采用的基础: 1.BT协议中采用的单

物联网MQTT协议分析和开源Mosquitto部署验证

在<物联网核心协议—消息推送技术演进>一文中已向读者介绍了多种消息推送技术的情况,包括HTTP单向通信.Ajax轮询.Websocket.MQTT.CoAP等,其中MQTT协议为IBM制定并力推,其具有开放.简单.轻量级以及易于实现的特点使得其即便在资源受限的环境中也能得到很好的使用,比如运行在资源紧缺型的嵌入式系统中或网络带宽非常昂贵的环境中,除此之外,它也被广泛用于遥感勘测.智能家居.能源监测和医疗应用程序等各个领域,是物联网的重要组成部分,将来可能会成为物联网的事实标准. 本篇文章将帮助

协议分析 - DHCP协议解码详解

协议分析 - DHCP协议解码详解 [DHCP协议简介] DHCP,全称是 Dynamic Host Configuration Protocol﹐中文名为动态主机配置协议,它的前身是 BOOTP,它工作在OSI的应用层,是一种帮助计算机从指定的DHCP服务器获取它们的配置信息的自举协议. DHCP使用客户端/服务器模式,请求配置信息的计算机叫做DHCP客户端,而提供信息的叫做DHCP的服务器.DHCP为客户端分配地址的方法有三种:手工配置.自动配置.动态配置. DHCP最重要的功能就是动态分配

linux 网络协议分析---3

本章节主要介绍linxu网络模型.以及常用的网络协议分析以太网协议.IP协议.TCP协议.UDP协议 一.网络模型 TCP/IP分层模型的四个协议层分别完成以下的功能: 第一层 网络接口层 网络接口层包括用于协作IP数据在已有网络介质上传输的协议.实际上TCP/IP标准并不定义与ISO数据链路层和物理层相对应的功能.相反,它定义像 地址解析协议(Address Resolution Protocol,ARP)这样的协议,提供TCP/IP协议的数据结构和实际物理硬件之间的接口. 第二层 网间层 网

网络协议分析

1. 网络模型 2. 协议分析 2.1协议架构 2. 2 以太网协议格式 2. 3 IP协议格式 2. 4 TCP协议格式 2. 5 UDP协议格式

http-live-streaming 协议分析

http-live-streaming 协议分析:不受限制的多媒体数据流的传输.协议支持媒体数据加密与流切换(例如不同码率).媒体数据创建后立即传输,播放接近实时.媒体数据通常采用HTTP进行传输.播放列表由一个有序的媒体URI列表和信息标签组成,每个媒体URI指向一个媒体文件,这个媒体文件是单个连续媒体流上的一个片断.为了播放媒体流,客户端首先获取播放列表文件,然后获取并播放播放列表中的每个媒体流文件.客户端依据下文定义方式重复加载播放列表文件以获取追加片断.播放列表必须是扩展的M3U播放列表

QQ2010协议分析系列(二) - 登录之第一篇(0x0091)

QQ2010协议分析第一篇 测试QQ:597789809 昵称:浪子无情 尝试QQ服务器IP:112.95.240.125 client IP:222.35.174.5(我的外网IP) 密码:这个算了吧 Send: 看到下面的数字很迷茫吧,不用着急,我慢慢解释 下面的文本是HEX字符串,是常用网络16进制文本方式. QQ常用消息包结构: 包头:02 //表示包的开头 1F 57 //QQ版本代码,这里表示QQ2010sp3版本 00 91 //包命令 58 16      //这个不是固定的,表