注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

snoopyxdy的博客

https://github.com/DoubleSpout

 
 
 

日志

 
 

thrift Tutorial 详解  

2015-04-22 14:08:09|  分类: python |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
最近有业务需要接触thrift,之前只是简单了解过,做下对 thrift 入门的笔记。
首先我们需要下载 shared.thrift 和 tutorial.thrift 两个文件,然后执行命令生成py文件:
命令代码示例:

thrift -r --gen <language> <Thrift filename>

执行命令:

thrift -r --gen py tutorial.thrift


1、我们先分析看看 shared.thrift 和 tutorial.thrift 两个文件,这两个文件定义了通信双方的接口和数据格式

先看下 shared.thrift 文件

namespace cpp shared
namespace d share // "shared" would collide with the eponymous D keyword.
namespace java shared
namespace perl shared
namespace php shared
namespace haxe shared

//namespace 是指单独为某种语言制定生成的命名空间,否则就以当时的文件名命名

//比如在这里设置 namespace py sharedxxxxxx

//就会生成 sharedxxxxxx 目录,在目录中有__init__文件


//定义一种数据类型,SharedStruct 第一个数值类型为inter32,第二个数据类型为string
struct SharedStruct {
1: i32 key
2: string value
}

//定义一个接口类
service SharedService {

//定义一个函数名称为 getStruct,返回 SharedStruct 类型返回值,参数第一个是inter32的值
SharedStruct getStruct(1: i32 key)
}

然后我们分析下 tutorial.thrift 文件

/**
* thrift支持的基础类型:
*
* bool 布尔
* byte 字节
* i16 16位整形
* i32 32位整形
* i64 64位整形
* double 64位浮点
* string 字符串
* binary 二进制,字节数组
* map<t1,t2> 字典,key,value
* list<t1> 数组
* set<t1> set,无重复项数组
*
*/

/**
* thrift 可以include包含其他文件

*/
include "shared.thrift"


/**
* thrift 可以使用 typedef 来自定义类型的名字
*/
typedef i32 MyInteger

/**
* thrift允许我们定义跨语言常量
*/
const i32 INT32CONSTANT = 9853
const map<string,string> MAPCONSTANT = {'hello':'world', 'goodnight':'moon'}

/**
* 我们也可以定义枚举,如果没有提供将从1开始
*/
enum Operation {
ADD = 1,
SUBTRACT = 2,
MULTIPLY = 3,
DIVIDE = 4
}

/**
struct 结构是一个基本的复杂数据结构,

* 需要一个整数的标示,一个类型,一个变量名和一个可选的默认值

* 可选的声明表示这个字段不是必须被包含在这个结构里的
*/
struct Work {
1: i32 num1 = 0,
2: i32 num2,
3: Operation op,
4: optional string comment,
}

/**
* 可以定义异常的类型struct结构体
*/
exception InvalidOperation {
1: i32 what,
2: string why
}

/**
* 定义一个service,就是接口类
* 可以通过extends用来继承其他 service
*/
service Calculator extends shared.SharedService {

/**
* 定义一个方法,它有返回值和参数
* 可选的定义一个他可能抛出的异常数组
* 注意参数的定义和异常的定义,需要在之前定义过他们
*/

void ping(),

i32 add(1:i32 num1, 2:i32 num2),

i32 calculate(1:i32 logid, 2:Work w) throws (1:InvalidOperation ouch),

/**
* oneway 修饰符表示这个方法客户端只是调用,并不关心它的返回值
* 所以这个方法的返回值必须是void


*/
oneway void zip()

}


2、我们现在分析thrift clinet的代码

import sys, glob sys.path.append('gen-py') sys.path.insert(0, glob.glob('../../lib/py/build/lib.*')[0]) from tutorial import Calculator from tutorial.ttypes import * from thrift import Thrift from thrift.transport import TSocket from thrift.transport import TTransport from thrift.protocol import TBinaryProtocol try: # Make socket transport = TSocket.TSocket('localhost', 9090) # Buffering is critical. Raw sockets are very slow transport = TTransport.TBufferedTransport(transport) # Wrap in a protocol protocol = TBinaryProtocol.TBinaryProtocol(transport) # Create a client to use the protocol encoder client = Calculator.Client(protocol) # Connect! transport.open() client.ping() print 'ping()' sum = client.add(1,1) print '1+1=%d' % (sum)

#实例化一个work类型,则个Work类型是在之前的thrift接口文件定义的 work = Work() work.op = Operation.DIVIDE work.num1 = 1 work.num2 = 0

#执行1除以0,会抛出错误 try:

quotient = client.calculate(1, work) print 'Whoa? You know how to divide by zero?' except InvalidOperation, io: print 'InvalidOperation: %r' % io

#执行15-10 work.op = Operation.SUBTRACT work.num1 = 15 work.num2 = 10 diff = client.calculate(1, work) print '15-10=%d' % (diff)  

#获取结构中第一个值 log = client.getStruct(1) print 'Check log: %s' % (log.value) # Close! transport.close() except Thrift.TException, tx: print '%s' % (tx.message)

其实客户端的一些程序都是调用方法,具体的方法实现我们要进一步看服务器那边的实现。


3、分析一下服务器那边的实现

import sys, glob
sys.path.append('gen-py')
sys.path.insert(0, glob.glob('../../lib/py/build/lib.*')[0])

from tutorial import Calculator
from tutorial.ttypes import *

from shared.ttypes import SharedStruct

from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol
from thrift.server import TServer

#定义实现接口类 CalculatorHandler
class CalculatorHandler:
def __init__(self):
self.log = {}

#定义ping方法
def ping(self):
print 'ping()'

#定义add方法
def add(self, n1, n2):
print 'add(%d,%d)' % (n1, n2)
return n1+n2
 

#定义 calculate 方法
def calculate(self, logid, work):
print 'calculate(%d, %r)' % (logid, work)

if work.op == Operation.ADD: #如果操作等于加
val = work.num1 + work.num2
elif work.op == Operation.SUBTRACT: #如果操作等于减
val = work.num1 - work.num2
elif work.op == Operation.MULTIPLY: #如果操作等于乘
val = work.num1 * work.num2
elif work.op == Operation.DIVIDE: #如果操作等于除
if work.num2 == 0:
x = InvalidOperation() #实例化异常
x.what = work.op
x.why = 'Cannot divide by 0'
raise x
val = work.num1 / work.num2
else: #如果op不在枚举中,那就抛出错误
x = InvalidOperation()
x.what = work.op
x.why = 'Invalid operation'
raise x
 

#实例化 sharedStruct 类,用来记录这次操作的logid的记录
log = SharedStruct()
log.key = logid
log.value = '%d' % (val)
self.log[logid] = log

return val
 

#获得根据logid获得记录的计算值
def getStruct(self, key):
print 'getStruct(%d)' % (key)
return self.log[key]

def zip(self):
print 'zip()'


#下面就是thrift启动服务的固定用法了
handler = CalculatorHandler()
processor = Calculator.Processor(handler)
transport = TSocket.TServerSocket(port=9090)
tfactory = TTransport.TBufferedTransportFactory()
pfactory = TBinaryProtocol.TBinaryProtocolFactory()

server = TServer.TSimpleServer(processor, transport, tfactory, pfactory)

# You could do one of these for a multithreaded server
#server = TServer.TThreadedServer(processor, transport, tfactory, pfactory)
#server = TServer.TThreadPoolServer(processor, transport, tfactory, pfactory)

print 'Starting the server...'
server.serve()
print 'done.'


其实thrift刚接触比较容易一头雾水,真正看懂了入门示例,感觉还是很好上手的


  评论这张
 
阅读(498)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2016