thrift文件编写

系统 1767 0

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)

}
      
    

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

thrift文件编写

我们可以让这个随便编写的脚本为我们完成一点点功能,比如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类型的实例化对象。

 

thrift文件编写


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论