zoukankan      html  css  js  c++  java
  • python thrift demo

    原文链接:https://www.bigdatasafe.org/post/41334.html

    简介
    Thrift最初由Facebook研发,主要用于各个服务之间的RPC通信,支持跨语言,常用的语言比如C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, and OCaml都支持。Thrift是一个典型的CS(客户端/服务端)结构,客户端和服务端可以使用不同的语言开发。既然客户端和服务端能使用不同的语言开发,那么一定就要有一种中间语言来关联客户端和服务端的语言,这种语言就是IDL(Interface Description Language)

    SRE实战,互联网时代守护先锋!让网站飞一会, 阿里云优惠促销大全。

    thrift使用流程
    明确要交互的数据格式和具体的方法,定义出thrift接口描述文件(英文叫做IntefaceDescription File)

    调用thrift工具,依据thrift接口文件,生成RPC代码;

    你的服务器端程序引用thrift生成的RPC代码,并实现其中的Search动作的逻辑,然后启动监听,等待客户端发来请求。
    客户端同样引入并调用RPC代码来与服务器端通信

    thrift IDL
    1. 基本类型
    thrift不支持无符号类型,因为很多编程语言不存在无符号类型,比如java

    bool: 布尔类型(True or False)
    byte: 有符号字节
    i16: 16位有符号整数
    i32: 32位有符号整数
    i64: 64位有符号整数
    double: 64位浮点数
    string: 字符串
    2. 容器类型
    集合中的元素可以是除了service之外的任何类型,包括exception。

    list <T> : 一系列由T类型的数据组成的有序列表,元素可以重复。会被转换成C++中的vector,Java中的ArrayList,脚本语言中的数组等。
    set<T>: 一系列由T类型的数据组成的无序集合,元素不可重复。会转换成C++中的set,Java中的HashSet、Python中的Set等
    map<K,V>: 一个字典结构,key为K类型,value为V类型,相当于Java中的HMap

    3. 结构体

    就像C语言一样,thrift也支持struct类型,目的就是将一些数据聚合在一起,方便传输管理。struct的定 义形式如下:

    struct People {
         1: required string name;
         2: required i32 age = 20;
         3: optional string sex;
    }

    可以看到,结构体中每一个域都有一个正整数标识符,这个标识符并不要求连续,但一旦定义,不建议再进行修改
    另外,每个域前都会有required或optional的限定,前者表示是必填域,后者则表示是可选域。域是可以有默认值的,比如上例中的“age”。
    如果一个域设置为optional且在构造结构体时没有给这个域赋值,那么在使用这个结构体时,就会忽略掉这个optional的域

    异常(exception)

    thrift支持自定义exception,规则和struct一样,如下:

    exception RequestException {
        1: i32 code;
        2: string reason;
    }

    除了使用exception来替代struct以外,“异常”这个类型,在语法上和刚才介绍过的结构体的用法是完全一致的。但是从语义上讲,exception和struct却大相径庭。exception是在远程调用发生异常时用来抛出异常用的

    服务(Service)
    服务的定义,与面向对象技术中定义一个接口很类似,而这些接口其实就是纯虚函数。thrift编译工具会根据服务的定义来产生相应的方法和函数。
    每个服务,都包括了若干个函数,每个函数包括了若干参数和一个返回值(返回值可以是void.
    (小技巧:返回值为void的函数,你可以在函数名前加上oneway标识符,将此函数以异步模式执行,这样在调用此函数后,函数会立即返回。)

    对于返回void的函数,thrift仍然会确保函数返回,这样就表示这个函数已被正确执行,且服务器端已有返回信息了。但是如果给void的函数前加上oneway,那么此函数的返回只能表示数据已经进入传输层,并不能表示服务器端已经收到并返回了数据

    service vulgar_detect{
        bool is_vulgar(1:string title),
        i32 calc(1: i32 num)
    }

    thrift编译工具

    在我们编写好thrift接口描述文件之后,thrift编译工具就要派上用场了,它的作用就是根据thrift接口描述文件来生成相应开发语言的RPC代码. 
    在终端下输入:

    thrift --gen ${开发语言} ${thrift接口描述文件}

    Transport

    Transport网络读写(socket,http等)抽象,用于和其他thrift组件解耦。
    Transport的接口包括:open, close, read, write, flush, isOpen, readAll。
    Server端需要ServerTransport(对监听socket的一种抽象),用于接收客户端连接,接口包括:listen, accept, close。
    python中Transport的实现包括:TSocket, THttpServer, TSSLSocket, TTwisted, TZlibTransport,都是对某种协议或框架的实现。还有两个装饰器,用于为已有的Transport添加功能,TBufferedTransport(增加缓冲)和TFramedTransport(添加帧)。
    在创建server时,传入的时Tranport的工厂,这些Factory包括:TTransportFactoryBase(没有任何修饰,直接返回),TBufferedTransportFactory(返回带缓冲的Transport)和TFramedTransportFactory(返回帧定位的Transport)。

    Protocol

    Protocol用于对数据格式抽象,在rpc调用时序列化请求和响应。
    TProtocol的实现包括:TJSONProtocol,TSimpleJSONProtocol,TBinaryProtocol,TBinaryPotocolAccelerated,TCompactProtocol。

    Processor

    Processor对stream读写抽象,最终会调用用户编写的handler以响应对应的service。具体的Processor有compiler生成,用户需要实现service的实现类。

    Server

    Server创建Transport,输入、输出的Protocol,以及响应service的handler,监听到client的请求然后委托给processor处理。
    TServer是基类,构造函数的参数包括:
    1) processor, serverTransport
    2) processor, serverTransport, transportFactory, protocolFactory
    3) processor, serverTransport, inputTransportFactory, outputTransportFactory, inputProtocolFactory, outputProtocolFactory
    TServer内部实际上需要3)所列的参数,1)和2)会导致对应的参数使用默认值。
    TServer的子类包括:TSimpleServer, TThreadedServer, TThreadPoolServer, TForkingServer, THttpServer, TNonblockingServer, TProcessPoolServer
    TServer的serve方法用于开始服务,接收client的请求。

    Code generated

    constants.py: 包含声明的所有常量
    ttypes.py: 声明的struct,实现了具体的序列化和反序列化
    SERVICE_NAME.py: 对应service的描述文件,包含了:
    Iface: service接口定义
    Client: client的rpc调用桩

    用法

    Thrift的用法实际上很简单,定义好IDL,然后实现service对应的handler(方法名、参数列表与接口定义一致接口),最后就是选择各个组件。需要选择的包括:Transport(一般都是socket,只是十分需要选择buffed和framed装饰器factory),Protocol,Server。

    依赖包安装:

    yum install thrift 
    yum install python-thrift

    IDL文件

    /*
    thrift接口定义文件
    */
    service HelloService {
        string say(1:string msg)
    }

    在编辑好定义文件后, 运行如下命令,生成thrift文件。可把hello目录移到当前目录下,便于后面调用。

    thrift -r -gen py hello.thrift

    server端代码:

    # coding: utf-8
    """
    thrift_client.py
    """
    import socket
    import sys
    from hello import HelloService
    from hello.ttypes import *
     
    from thrift.transport import TSocket
    from thrift.transport import TTransport
    from thrift.protocol import TBinaryProtocol
    from thrift.server import TServer
    class HelloServiceHandler:
        def say(self, msg):
            ret = "Received: " + msg
            print ret
            return ret
    handler = HelloServiceHandler()
    processor = HelloService.Processor(handler)
    transport = TSocket.TServerSocket("localhost", 9090)
    tfactory = TTransport.TBufferedTransportFactory()
    pfactory = TBinaryProtocol.TBinaryProtocolFactory()
    server = TServer.TSimpleServer(processor, transport, tfactory, pfactory)
    print "Starting thrift server in python..."
    server.serve()
    print "done!"

    client端代码:

    # coding: utf-8
    """
    thrift_client.py
    """
     
    import sys
    from hello import HelloService
    from thrift import Thrift
    from thrift.transport import TSocket
    from thrift.transport import TTransport
    from thrift.protocol import TBinaryProtocol
    try:
        transport = TSocket.TSocket('localhost', 9090)
        transport = TTransport.TBufferedTransport(transport)
        protocol = TBinaryProtocol.TBinaryProtocol(transport)
        client = HelloService.Client(protocol)
        transport.open()
        print "client - say"
        msg = client.say("Hello!")
        print "server - " + msg
        transport.close()
    except Thrift.TException, ex:
        print "%s" % (ex.message)

    运行结果:

    server端:

    [root@wangjq thrift]# python server.py 
    Starting thrift server in python...
    Received: Hello!

    client端:

    [root@wangjq thrift]# python client.py 
    client - say
    server - Received: Hello!

    小结

    本文只是一个简单的示例,在实际项目中,一般会基于zookeeper来注册和管理服务的thrift状态,并对server和client进一步封装,便于在项目各个模块中调用。

  • 相关阅读:
    工厂设计模式
    二分查找(java实现)
    集合
    JS中,根据div数值判断弹出窗口
    用JS,打印正立三角形
    用JS,打印99乘法表
    用JS,求斐波那契数列第n项的值
    用JS 循环做一个表格
    JS中,如何判断一个被转换的数是否是NaN
    用JS写一个简单的程序,算出100中7的倍数的最大值
  • 原文地址:https://www.cnblogs.com/wangjq19920210/p/12024448.html
Copyright © 2011-2022 走看看