最近有业务需要接触thrift,之前只是简单了解过,做下对 thrift 入门的笔记。
首先我们需要下载 shared.thrift 和 tutorial.thrift 两个文件,然后执行命令生成py文件:
命令代码示例:
thrift -r –gen
执行命令:
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
数组 - set
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刚接触比较容易一头雾水,真正看懂了入门示例,感觉还是很好上手的