thrift初窥
本文按照以下结构介绍thrift
1. thrift是什么?
2. thrift能做什么
3. thrift和其他类似东西的对比
4. 我们使用thrift要做什么
好,先按照上面结构介绍。
1. thrift是什么?
官网上介绍得我不在累述,自己google其他关于thrift的文章,会有很多,比如"是apache的一个项目,和facebook有关系"等。我总结一句话:
thrift是跨语言,server和client通信的一个框架,支持多种协议,二进制,文本http,json等方式,提供高效的数据传输方式。
2. thrift能做什么?
thrift只负责对数据进行处理,然后在网络内进行传输的工作。不要认为thrift能在*.thrift文件中定义调度之类的工作。
3. thrift和其他东西对比
网上同thrift人们经常对比的dubbo,阿里巴巴的东西,还没研究。只说自己想对比的。
twisted。 python的一个网络编程框架。
twisted可thrift其实没有可比性,twisted客户端和服务器端都要求使用python,而thrift却不必,支持的语言很多,大众语言基本都有。而作为一个python程序员,自认为twisted很曲折的学习曲线。thrift的学习却很平滑,平滑。也就是说,如果你熟悉你所使用的语言,写一个thrift服务相当简单。当然了,twisted的作用可不是这一个。
cheerypy。python的一个网络编程框架。
服务器端同客户端的数据传输最让人容易想到的是http协议传输。所以,任何一个做BS的架构都可以做类似工作,只是别有界面而已。thrift说自己使用了二进制流进行数据传输,是高效的,而普通的http协议是文本传输,或者xml,或者json,所以在数据传输上thrift是高效的。关于这一点,需要具体看你项目中是否有类似需求,如果在2台机器之间,你们传输的只是一些配置文件之类的工作,完全没有必要。如果你在2台机器之间传输的是大日志,不错,可以考虑。
4. 使用thrift我们要做什么?
按以下结构介绍。
a. 学习安装
b. 学习*.thrift文件的编写。
c. 使用thrift命令生成协议文件等。
d. 编写自己的服务器端。
e. 编写自己的客户端。
f. 测试。
a. 安装thrift.(windows下)
安装exe格式吧,windows你不用关心什么mingw, 到http://www.apache.org/dyn/closer.cgi?path=/thrift/0.8.0/thrift-0.8.0.exe下载一个文件。
。
下载成功后在windows下使用这个文件有2种方法。1.将这个文件copy至项目目录,同*.thrift文件同目录。2将这个文件copy至c:/windows目录,一般windows目录都是键入到环境变量的。像我的就是:
, 在C:\Windows文件夹里。并且将文件的-0.8.0去掉了,方便使用命令。如果你愿意,写成什么都行。我这里玩了下,写成1.exe了。
照样正确。不过最好还是改过来,免的自己忘了自己这么玩过。这里就表示可以使用在任意位置使用thrift命令了。
b. thrift文件的编写。
我们知道,计算机语言必须有一个编译器,不管是C,python,php,python和php核心东西都是c写的,有人在说C是什么写的。或者问得不对,C的编译器是什么写的,因为一门语言的语法只是人们定义的一种格式,而最重要的是解析这些“代码”的编译器,有人说C的编译器也是C写的,有人不明白,追问为什么,那么最终其实可以解释成高阶的编译器逐渐在计算机语言发展的过程中沿用了历史给我们的遗产。那thrift这里总是在告诉我们一个名词,叫The Thrift interface definition language(IDL), thrift接口定义语言。由名称我们知道,这门语言是定义接口的,熟悉java的朋友一定非常清楚这个名词,不做具体业务的一门语言。那它有没有其他语言的特征呢,首先已经由他不做具体业务处理知道他少东西。但是他能做另外的事。
除了定义服务接口,他还能定义数据类型。但他不向内存申请空间来他任何和这个数据类型有关的操作,而只是做将这你所编写的*.thrift文件进行转型,转为你所熟悉的语言的代码!
所以,thrift是什么,是一个代码转换框架,将*.thrift转换为你说熟悉的语言,并且完成了一些代码,减少了你的代码编写量,但有学习成本。
至于语法请参看http://hi.baidu.com/o%CB%AF%D1%DB%EB%FC%EB%CA%B5%C4%D6%EDo/blog/item/6d1d4dac9f66b1a9ca130c37.html,网络很多这方面的东西。
现在先做个demo:
1. 先建立一个文件夹。
里面什么都没有。
2. 建议一个test.thrift文件。
新建立一个thrifttest.thrift文件了,但里面什么都没有。需要你自己编写thrifttest.thrift文件
struct File { 1:string path, 2:string data, } service HelloWorld { void ping() string copy(1:string path) }
。我们还需要做文件copy的操作。从服务器端copy文件到客户端。因为这样更符合使用thrift使用的条件。
有意思的编辑thrift文件,写个string copy(1:string path),把方法的返回值,方法名,方法参数都已经确认好了。即结构为 【返回值类型 方法名(参数类型 参数名称)】注意,这里如果是多个结构体,定义参数名称的时候最好不一样。
3. 使用命令生成代码
没有错误。表示代码生成了。这里thrifttest目录是服务器端
没有错误。表示代码生成了。这里thrifttest-client是客户端。
4. 编写服务器端代码。
#!/usr/bin/env python import sys sys.path.append('../gen-py') from thrifttest import HelloWorld from thrifttest.ttypes import * from thrift.transport import TSocket from thrift.transport import TTransport from thrift.protocol import TBinaryProtocol from thrift.server import TServer import socket class HelloWorldHandler: def __init__(self): self.log = {} def ping(self): print "ping()" def copy(self, path): print 'path',path with open(path, "rb") as f: data = f.read() return data handler = HelloWorldHandler() processor = HelloWorld.Processor(handler) transport = TSocket.TServerSocket("localhost",30303) tfactory = TTransport.TBufferedTransportFactory() pfactory = TBinaryProtocol.TBinaryProtocolFactory() server = TServer.TSimpleServer(processor, transport, tfactory, pfactory) print "Starting python server..." server.serve() print "done!"
注意这里的handler有2个处理方法,一个是ping(),一个是copy方法。ping方法是检查当前是否连接。copy做我们具体的业务,这里我们做的是读文件,你也可以用这个方法来写一个数据库查询,等等,反正这里已经独立出来了,只不过返回的数据我们定义的是string类型。别的类型你可以自己测试。
那么当前服务器端程序目录结构就是:
5. 编写客户端代码.
#!/usr/bin/env python import sys sys.path.append('../gen-py') from thrifttest import HelloWorld from thrifttest.ttypes import * from thrifttest.constants 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', 30303) # 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 = HelloWorld.Client(protocol) # Connect! transport.open() client.ping() print "ping()" data = client.copy("D:\\helloworld.html") print data transport.close() except Thrift.TException, tx: print "%s" % (tx.message)
这里所有个client可以调用我们服务器端方法。参数也是,简直就是像在一台机器上执行一样。0-0,我就是在一台机器上执行的,不过是2个进程而已,玩笑。也算进程间通信了。。。
当前代码结构如下图:
好。测试。
服务器端启动:
Starting python server...
客户端启动:
Sping() dfslfdjslfjdsldfjlskfjlsdjflsjdol
在客户端立马有了一段字符串,这段字符串d:/helloworld.html的内容。
而此时在服务器端打印出:
Starting python server... ping() path D:\helloworld.html
现在把文件变成10M的
修改客户端代码:
data = client.copy("D:\\nEOiMAGING_3.1.2.104_DownG.com.rar") with open("E://test.rar", 'wb') as f: f.write(data) end_time = time.time() all_time = end_time - start_time print all_time
执行结束后E盘有了 test.rar文件,输出
ping() 0.771000146866
时间是很短的。当然这是12M文件。不能说明什么问题。我们换个大的。
换成一个一个多G的文件。这时可能就要出错。
在客户端提示说:
ping() TSocket read 0 bytes
而服务器端提供的错误提示:
File "E:/workspace/thrifttest/gen-py/thrifttestservice.py", line 27, in copy data = f.read() MemoryError
但是出错并不影响当前服务的继续运行。
所以,thrift并不是想象中的那么高深,每个技术看他官方 文档的时候,都说的玄乎,不管是python介绍,还是thrift,django,scrapy,说的是自己厉害的,其实咱做技术的更应该关心那些场景他不适合。别乱用技术。别图新鲜胡乱用在某个项目中。