• thrift文件编写


    1.thrift的数据类型。(这里主要为翻译官方文档)

      a. 基本数据类型

        1) boolean型,值为true或false

        2) byte型,值为单字节字母

        3) i16型,值长度为16位的integer带符号数字.

        4) i32型,值长度为32位的integer带符号数字.

        5) i64型,值长度为64位的integer带符号数字.

        6) double型,值长度为64的浮点数.

        7) string型,字符串或者binary数据。

      b. 结构体

        有点类似c的结构体。不怎么懂c的同学可以理解为不带方法的类,只有属性而已。

        型如:

        

    struct Work {
    1: i32 num1 = 0,
    2: i32 num2,
    3: Operation op,
    4: optional string comment,
    }

      c. 容器

        1) list类型。

          指一组有序元素的集合,类似于java的ArrayList类。

        

    typedef i32 MyInteger
    MyInteger a;
    struct hello{
        list<MyInteger> d; }

    指hello结构体中含有一个list类型的数据,且里面的元素都必须是a数据类型的MyInteger数据类型的数据,主要这里的typedef起一个别名的作用。

        2) set类型

          一个不可重复的排序元素的集合,类似java的hashset,python的set.使用同list

        3) map<type1,type2>类型。

          使用如:

    map<string,string> MAPCONSTANT = {'hello':'world', 'goodnight':'moon'}

        4) 枚举类型

    2. 服务

      有了数据结构,那么就该对数据进行操作。thrift这里所说的服务,不可能针对我们自己的业务逻辑,而是指的是服务端从端口读取数据,客户端传入数据的一套方法。

    service <服务名>{
         <返回类型> <方法名>(参数) throws <异常>
    }

    3. 实践:

    根据前面所说数据类型和结构体,编写如下thrift文件,名为 test.thrift

    i32 a;
    i32 b;
    string c;
    list<string> d;
    map<string, string> e = {"hello" : "world", "dd" : "ee"};
    
    struct f{
        1:a,
        2:b,
        3:c=2,
        4:d="ceshi",
        5:e,
    }
    
    service Hello{
        f get_f(1:f gg) throws (Exception, e)
    }

    以上代码使用thrift的标准命令(thrift.exe -gen py test.thrift)是不成功,因为语法还是不正确!

    修改

    1.常量量如a,b,c,d, e要使用const修饰。

    2. 如果都使用了const修饰,但有;号,还是不成功,尽管有的人说thrift对;不敏感,那还是估计看版本的,这里我使用的是最新的0.8版本。也就是说,如果你是一个java或者php程序员,请注意没有";"

    3. 静态变量请赋值,如const i32 a = "helloworld"

    4. 结构体内部的属性请指定参数类型,因为结构体内部属性和外部的静态属性没有任何关系。

    5. 异常之间没有“,”分割,以空格代替

    6. Exception类型请定义。

    7. throws参数也要指定是第几个参数

    好了,修改后的thrift脚本变为

    const i32 a = 1
    const i32 b = 2
    const string c = "helloworld"
    const list<string> d = "test"
    const map<string, string> e = {"hello" : "world", "dd" : "ee"}
    
    struct f{
        1:i32 a,
        2:i32 b,
        3:string c,
        4:list<string> d=["ceshi"],
        5:map<string,string> e = {"hello":"world"},
    }
    exception Exception{
        1:i32 what;
        2:string where;
    }
    service Hello{
        f get_f(1:f gg) throws (1:Exception e)
    }

    稍微有那么一点像生产环境了,生成代码结构:

    我们可以让这个随便编写的脚本为我们完成一点点功能,比如get_f让他对结构体f的对象gg的各种值计算,当然生成环境也可以集成数据库了。

    那么现在需要几个数据通信接口了。

    1. 读取数据:readMessageBegin()

      (fname, mtype, rseqid) = self._iprot.readMessageBegin()

      从端口读取请求流,获取3个值。

      readMessageEnd() 读取数据结束。

    2. readStructBegin() 开始读取结构体

      readStructEnd() 读取结构体结束

    3. readFieldBegin() 读取属性开始

      readFieldEnd()

    4. readMapBegin()读取map开始

      readMapEnd()读取map结束。

    这里的数据接口还有很多,不一一列举,因为我们在实际使用thrift的时候,只要不类似于修改thrift源码的操作,都不需要关心这些具体的数据操作。

    接下来我们做客户端和服务端的操作,同时在服务端进行具体业务的处理。

    1. 编写借口类.

      

    import sys
    sys.path.append("../gen-py")
    from cc import Hello
    
    from cc import ttypes
    
    class My_Handler(Hello.Iface):
    
        def get_f(self, gg):
            #对对象gg进行梳理
            gg.a = gg.a + gg.b
            gg.b = gg.a - gg.b
            return gg

    官方事例的CalculatorHandler是不继承Iface的,而我这里采用继承Hello.Iface,并没有别的深意,是表示一定要有我们定义thrift文件的get_f方法。假如我们的逻辑更加复杂,handler处理里有数据库操作等等,继承不继承Iface都是可以的。

    官方的handler(部分):

    class CalculatorHandler:
        def __init__(self):
            self.log = {}
    
        def ping(self):
            print 'ping()'
    
        def add(self, n1, n2):
            print 'add(%d,%d)' % (n1, n2)
            return n1+n2

    接下来要对这个handler要对这个hander进行处理:

    import sys
    sys.path.append("../gen-py")
    from cc import Hello
    
    from cc import ttypes
    
    class My_Handler(Hello.Iface):
    
        def get_f(self, gg):
            #对对象gg进行梳理
            gg.a = gg.a + gg.b
            gg.b = gg.a - gg.b
            return gg
    
    handler = My_Handler()
    process = Hello.Processor(handler)
    from thrift.transport.TSocket import TServerSocket
    server = TServerSocket(host="localhost", port = 9090)
    from thrift.transport.TTransport import TBufferedTransportFactory
    tfactory = TBufferedTransportFactory()
    from thrift.protocol.TBinaryProtocol import TBinaryProtocolFactory
    bfactory = TBinaryProtocolFactory()
    
    from thrift.server.TServer import  TSimpleServer
    servers = TSimpleServer(process, server, tfactory, bfactory)
    print "starting the server..."
    servers.serve()
    print "done..."

    直接上代码了。注意,这里的TServerSocket一定要指定,因为官方的类初始化时host赋初值居然写的none,等于没有写麽。

    class TServerSocket(TSocketBase, TServerTransportBase):
      """Socket implementation of TServerTransport base."""
    
      def __init__(self, host=None, port=9090, unix_socket=None):

    一个没有host的服务,可以想象会是什么样子,使用netstat -na查看端口:

     TCP    [::]:9090              [::]:0                 LISTENING
    

    就是没有host导致的情况。

    一个host定义为localhost的服务,使用netstat -na查看端口:

    TCP    127.0.0.1:9090         0.0.0.0:0              LISTENING
    

    接下来编写客户端,客户端的编写主要是是实例化Hello.Client对象

    __author__ = 'CLTANG'
    #! -*- encoding:utf-8 -*-
    
    '''
        客户端
    '''
    
    import sys
    sys.path.append("../gen-py")
    from cc import Hello
    from cc import ttypes
    
    
    from thrift.transport import TSocket
    from thrift.transport import TTransport
    from thrift.protocol.TBinaryProtocol import TBinaryProtocol
    transport = TSocket.TSocket('localhost', 9090)
    
    # Buffering is critical. Raw sockets are very slow
    transport = TTransport.TBufferedTransport(transport)
    
    # Wrap in a protocol
    protocol = TBinaryProtocol(transport)
    client = Hello.Client(protocol)
    
    transport.open()
    
    ff = ttypes.f(a=1,b=2)
    
    results = client.get_f(ff)
    print results
    transport.close()

    执行客户端程序,最终将输出:

    f(a=3, c='helloworld', b=1, e={'cc': 'dd', 'ee': 'ff'}, d=['hello', 'world'])
    

    达到了我们最早定义在test.thrift中的service的内容,即传入f类型的实例化对象,调用get_f方法,返回一个经过处理的f类型的实例化对象。

  • 相关阅读:
    转:超实用!聊聊图标设计流程及小技巧
    WPF 高性能画心电图
    转:WPF .NET 4.0下实现外发光效果
    (转)翻译:使用ViewModel模式来简化WPF的TreeView
    (转)How to get TreeViewItem from HierarchicalDataTemplate item?
    (转)WPF中的TreeView入门
    (转) WPF Treeview 学习 图标,checkbox,右键菜单
    linux中的定时任务--cron任务
    tar命令的使用与学习
    linux学习一
  • 原文地址:https://www.cnblogs.com/CLTANG/p/2694495.html
Copyright © 2020-2023  润新知