• 【Python】Thrift rpc 接口测试 python


    author: jwesh
    date: 2022.08.06

    Thrift rpc 接口测试 python

    在 window 上使用 python + thrift 库来进行接口测试,通过官网下载的 thrift-0.11.0.exe 进行接口文件生成

    一 .基础的命令

    默认的命令

    thrift-0.11.0.exe -r  --gen py xAnti.thrift
    
    • 1

    修改输入路径的命令(设置gen-*包的输出目录(默认值是当前目录),他会生成gen-py目录)

    thrift-0.11.0.exe -o ../src/xAnti/ --gen py xAnti.thrift
    
    • 1

    修改输入路径的命令(为生成的文件设置输出位置(不会创建gen-*文件夹))

    thrift-0.11.0.exe -out ../src/xAnti/ --gen py xAnti.thrift
    
    • 1

    使用docker: thrift 构建代码(兼容mac、liunx、window;避免thrift版本冲突)

    cd /Users/apple/jayzhen/qadev/qadev-test-script/thrift_test
    docker run --rm --privileged -v "$PWD:/data" thrift:0.11.0 thrift -out /data/src/kgc/lib --gen py /data/thrift-files/kgc_bridge.thrift
    
    如果有`include`其他文件(注意生成后的文件引入问题)
    
    docker run --rm --privileged -v "$PWD:/data" thrift:0.11.0 thrift -r -out /data/src/jayzhen --gen py /data/thrift-files/doc/jayzhen_storage.thrift
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    如果想在指定目录下生成指定的目录层级

    1. 自己先创建好对应的目录树,然后在-out加上路径
    2. 在thrift文件中的namespace后面定义包空间
    3. 注意thrift文件名一定要放到最后面,不然会报错Unrecognized option

    二. thrift的sever设计

    在服务器端启动 thrift 框架的部分代码比较简单,不过在写这些启动代码之前需要先确定服务器采
    用哪种工作模式对外提供服务,Thrift 对外提供几种工作模式,例如:TSimpleServer
    TNonblockingServerTThreadPoolServerTThreadedSelectorServer 等模式,每种服务模
    式的通信方式不一样,因此在服务启动时使用了那种服务模式,客户端程序也需要采用对应的通信
    方式。

    另外,Thrift支持多种通信协议格式:TCompactProtocolTBinaryProtocol
    TJSONProtocol 等,因此,在使用 Thrift 框架时,客户端程序与服务器端程序所使用的通信
    协议一定要一致,否则便无法正常通信。

    三. thrift 的 client 设计

    有上面生成的 gen-py 文件夹,所有接口对应的服务代码都在里面了,我们需要设计客户端代码来进行调用

    1.创建一个传输层对象(TTransport),具体采用的传输方式是 TFramedTransport ,要与服务器端保持一致,这里的THRIFT_HOST, THRIFT_PORT分别是 Thrift 服务器程序的主机地址和监听端口号,这里的 2000socket 的通信超时时间;即:

    • java
    m_transport =new TFramedTransport(newTSocket(THRIFT_HOST,THRIFT_PORT, 2000));
    
    • 1
    • python
    tsocket = TSocket.TSocket(host, port)
    transport = TTransport.TFramedTransport(tsocket)
    
    • 1
    • 2

    2.创建一个通信协议对象(TProtocol),具体采用的通信协议是二进制协议,这里要与服务器端保持一致,即:

    • java
    TProtocol protocol =new TBinaryProtocol(m_transport);
    
    • 1
    • python
    protocol = TBinaryProtocol.TBinaryProtocol(transport)
    
    • 1

    3.创建一个Thrift客户端对象(TestThriftService.Client),Thrift的客户端类 TestThriftService.Client 已经在文件TestThriftService.java 中,由Thrift编译器自动为我们生成,即:

    • java
    TestThriftService.ClienttestClient =new TestThriftService.Client(protocol);
    
    • 1
    • python
    client = Client(protocol)
    
    • 1

    4.打开 socket,建立与服务器直接的 socket连 接,即:

    • java
    m_transport.open();
    
    • 1
    • python
    transport.open()
    
    • 1

    5.通过客户端对象调用服务器服务函数getStr,即:

    • java
    String res = testClient.getStr("test1","test2");
    System.out.println("res = " +res);
    
    • 1
    • 2
    • python
    dta = UserNumReq()
    dta.Uid = 115775
    dta.NumTypes = [1, 2]
    result = client.get_user_num(dta)
    
    • 1
    • 2
    • 3
    • 4

    6.使用完成关闭socket,即:

    • java
    m_transport.close();
    
    • 1
    • python
    transport.close()
    
    • 1

    这里有以下几点需要说明:

    1. 在同步方式使用客户端和服务器的时候,socket 是被一个函数调用独占的,不能多个调用同时使用一个 socket,
      例如通过 m_transport.open() 打开一个socket,此时创建多个线程同时进行函数调用,这时就会报错,
      因为 socket 在被一个调用占着的时候不能再使用;

    2. 可以分时多次使用同一个socket进行多次函数调用,即通过 m_transport.open() 打开一个socket之后,
      你可以发起一个调用,在这个次调用完成之后,再继续调用其他函数而不需要再次通过 m_transport.open()
      打开socket;

    三. 通信之间的关注点

    1.Thrift 的服务器端和客户端使用的通信方式要一样,否则便无法进行正常通信;

    Thrift的服务器端的种模式所使用的通信方式并不一样,因此,服务器端使用哪种通信
    方式,客户端程序也要使用这种方式,否则就无法进行正常通信了。例如,上面的代码2.3
    中,服务器端使用的工作模式为 TNonblockingServer,在该工作模式下需要采用的传输
    方式为 TFramedTransport,也就是在通信过程中会将 tcp 的字节流封装成一个个的帧,
    此时就需要客户端程序也这么做,否则便会通信失败。
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2.在服务器端或者客户端直接使用 IDL 生成的接口文件时,可能会遇到下面两个问题:

    [1] Cannotreduce the visibility of the inherited method fromProcessFunction
    
    [2] The typeTestThriftService.Processor.getStr must implement theinherited abstract methodProcessFunction.isOneway()
    
    • 1
    • 2
    • 3

    问题产生的原因:

    问题[1] 是继承类的访问权限缩小所造成的;
    问题[2] 是因为存在抽象函数isOneWay所致;
    
    • 1
    • 2

    解决办法:

    问题[1]的访问权限由protected修改为public;
    问题[2]的解决办法是为抽象函数添加一个空的函数体即可。
    
    • 1
    • 2

    3.还有就是thrift的版本和生成代码的有必要加上版本号

    四. thrift 基本语法

    1. 编写IDL文件时需要注意的问题

    函数的参数要用数字依序标好,序号从1开始,形式为:“序号:参数名”;
    
    每个函数的最后要加上“,”,最后一个函数不加;
    
    在IDL中可以使用/*……*/添加注释
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2. IDL支持的数据类型

    IDL大小写敏感,它共支持以下几种基本的数据类型

    string, 字符串类型,注意是全部小写形式;例如:string aString
    
    i16, 16位整形类型,例如:i16 aI16Val;
    
    i32,32位整形类型,对应C/C++/java中的int类型;例如:      I32  aIntVal
    
    i64,64位整形,对应C/C++/java中的long类型;例如:I64 aLongVal
    
    byte,8位的字符类型,对应C/C++中的char,java中的byte类型;例如:byte aByteVal
    
    bool, 布尔类型,对应C/C++中的bool,java中的boolean类型; 例如:bool aBoolVal
    
    double,双精度浮点类型,对应C/C++/java中的double类型;例如:double aDoubleVal
    
    void,空类型,对应C/C++/java中的void类型;该类型主要用作函数的返回值,例如:void testVoid(),
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    除上述基本类型外,ID还支持以下类型:

    map,map类型,例如,定义一个map对象:map newmap;
    
    set,集合类型,例如,定义set对象:set aSet;
    
    list,链表类型,例如,定义一个list对象:list aList;
    
    • 1
    • 2
    • 3
    • 4
    • 5

    3. 在Thrift文件中自定义数据类型

    在IDL中支持两种自定义类型:枚举类型和结构体类型,具体如下:

    enum, 枚举类型,例如,定义一个枚举类型:
    
    enum Numberz
    {
      ONE = 1,
      TWO,
      THREE,
      FIVE = 5,
      SIX,
      EIGHT = 8
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    注意: 枚举类型里没有序号

    struct,自定义结构体类型,在IDL中可以自己定义结构体,对应C中的struct,c++中的struct和class,java中的class。例如:
    
    struct TestV1 {
           1: i32 begin_in_both,
           2: string old_string,
           3: i32 end_in_both
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    注意: 在 struct 定义结构体时需要对每个结构体成员用序号标识:“序号: ”。

    4. 定义类型别名

    Thrift的IDL支持C/C++中类似typedef的功能,例如:

    typedef i32  Integer 
    
    • 1

    就可以为i32类型重新起个名字Integer。

    5. 支持的数据类型、数据传输格式、数据传输方式和服务器类型

    数据类型

    Base Types:基本类型
    Struct:结构体类型
    Container:容器类型,即List、Set、Map
    Exception:异常类型
    Service: 定义对象的接口,和一系列方法
    
    • 1
    • 2
    • 3
    • 4
    • 5

    数据传输格式
    Thrift支持二进制和文本2类协议,二进制协议比本文协议更优。但是文本协议在某些情况下更有用(如debug)。

    TBinaryProtocol –二进制编码格式
    TCompactProtocol –使用Variable-Length Quantity (VLQ) 编码对数据进行压缩,高效
    TJSONProtocol – JSON编码格式
    TSimpleJSONProtocol –只提供JSON只写协议, 生成的文件很容易通过脚本语言解析。
    TDebugProtocol – 使用易懂的可读的文本格式,以便于debug
    TDenseProtocoal – 和TCompactProtocol相似,但在发送时省略了meta信息,在接收端重新加上。还在实验中,java实现还不可用。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    数据传输方式

    TSocket -阻塞式socketI/O
    TFramedTransport – 以frame为单位进行传输,要求服务器为非阻塞式方式。
    TFileTransport – 以文件形式进行传输,不支持java方式,但实现起来也很简单。
    TMemoryTransport – 使用内存I/O,如同Java中的ByteArrayOutputStream实现。
    TZlibTransport – 使用zlib进行压缩, 与其他传输方式联合使用。当前无java实现。
    
    • 1
    • 2
    • 3
    • 4
    • 5

    服务器类型

    TSimpleServer –单线程服务模型,使用标准的阻塞式I/O,常用于测试
    TThreadPoolServer – 多线程服务模型,使用标准的阻塞式I/O。
    TNonblockingServer – 多线程服务模型,使用非阻塞式I/O(需使用TFramedTransport数据传输方式)
    
    • 1
    • 2
    • 3
  • 相关阅读:
    RepVGG网络学习记录
    jQuery小结四
    快速幂算法
    AOP+自定义注解+Redis实现分布式缓存
    驱动开发:内核中实现Dump进程转储
    Word文档中书签使用注意事项
    【原创】xenomai UDD介绍与UDD用户态驱动示例
    代码随想录9——字符串:KMP算法求解28.实现strStr()
    elementui时间日期组件右边自定义图标
    两种方式实现websocket获取数据库查询进度
  • 原文地址:https://blog.csdn.net/u013948858/article/details/126190341