分享
Golang、Php、Python、Java基于Thrift0.9.1实现跨语言调用
lion.net · · 3994 次点击 · · 开始浏览这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。
目录:
一、什么是Thrift?
1) Thrift内部框架一瞥
2) 支持的数据传输格式、数据传输方式和服务模型
3) Thrift IDL
二、Thrift的官方网站在哪里?
三、在哪里下载?需要哪些组件的支持?
四、如何安装?
五、Golang、Java、Python、PHP之间通过Thrift实现跨语言调用
1) Golang 客户端和服务端的实现及交互
2) python 客户端的实现与golang 服务端的交互
3) php 客户端的实现与golang 服务端的交互
4) java 客户端的实现与golang 服务端的交互
六、扩展阅读
一、什么是Thrift
Thrift是一种可伸缩的跨语言服务的发展软件框架。它结合了功能强大的软件堆栈的代码生成引擎,以建设服务。
Thrift是facebook开发的,07年4月开放源代码,08年5月进入apache孵化器。创造Thrift是为了解决facebook系统中各系统间大数据量的传 输通信以及系统之间语言环境不同需要跨平台的特性。所以thrift可以支持多种程序语言,例如: C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, and OCaml. (目前0.9.1版本已经开始支持golang语言)在多种不同的语言之间通信thrift可以作为二进制的高性能的通讯中间件,支持数据(对象)序列化和多种类型的RPC服务。
Thrift允许你定义一个简单的定义文件中的数据类型和服务接口。以作为输入文件,编译器生成代码用来方便地生成RPC客户端和服务器通信的无缝跨编程语言。简而言之,开发者只需准备一份thrift脚本,通过thrift code generator(像gcc那样输入一个命令)就能生成所要求的开发语言代码。
类似Thrift的工具,还有Avro、protocol buffer,但相对于Thrift来讲,都没有Thrift支持全面和使用广泛。
1) thrift内部框架一瞥
按照官方文档给出的整体框架,Thrift自下到上可以分为4层:
+-------------------------------------------+
| Server | -- 服务器进程调度
| (single-threaded, event-driven etc) |
+-------------------------------------------+
| Processor | -- RPC接口处理函数分发,IDL定义接口的实现将挂接到这里面
| (compiler generated) |
+-------------------------------------------+
| Protocol | -- 协议
| (JSON, compact etc) |
+-------------------------------------------+
| Transport | -- 网络传输
| (raw TCP, HTTP etc) |
+-------------------------------------------+
Thrift实际上是实现了C/S模式,通过代码生成工具将接口定义文件生成服务器端和客户端代码(可以为不同语言),从而实现服务端和客户端跨语言的支持。用户在Thirft描述文件中声明自己的服务,这些服务经过编译后会生成相应语言的代码文件,然后用户实现服务(客户端调用服务,服务器端提服务)便可以了。其中protocol(协议层, 定义数据传输格式,可以为二进制或者XML等)和transport(传输层,定义数据传输方式,可以为TCP/IP传输,内存共享或者文件共享等)被用作运行时库。
2)支持的数据传输格式、数据传输方式和服务模型
(a)支持的传输格式
TBinaryProtocol – 二进制格式.
TCompactProtocol – 压缩格式
TJSONProtocol – JSON格式
TSimpleJSONProtocol –提供JSON只写协议, 生成的文件很容易通过脚本语言解析。
TDebugProtocol – 使用易懂的可读的文本格式,以便于debug
(b) 支持的数据传输方式
TSocket -阻塞式socker
TFramedTransport – 以frame为单位进行传输,非阻塞式服务中使用。
TFileTransport – 以文件形式进行传输。
TMemoryTransport – 将内存用于I/O. java实现时内部实际使用了简单的ByteArrayOutputStream。
TZlibTransport – 使用zlib进行压缩, 与其他传输方式联合使用。当前无java实现。
(c)支持的服务模型
TSimpleServer – 简单的单线程服务模型,常用于测试
TThreadPoolServer – 多线程服务模型,使用标准的阻塞式IO。
TNonblockingServer – 多线程服务模型,使用非阻塞式IO(需使用TFramedTransport数据传输方式)
3) Thrift IDL
Thrift定义一套IDL(Interface Definition Language)用于描述接口,通常后缀名为.thrift,通过thrift程序把.thrift文件导出成各种不一样的代码的协议定义。IDL支持的类型可以参考这里:http://thrift.apache.org/docs/types
二、Thrift的官方网站在哪里?
三、在哪里下载?需要哪些组件的支持?
Thrift的官方下载地址在这里:http://www.apache.org/dyn/closer.cgi?path=/thrift/0.9.1/thrift-0.9.1.tar.gz
(现在官网打包后的0.9.1版本在make的时候会出各种问题,后文会介绍不建议使用官网提供的0.9.1包)
Thrift的安装依赖,以及相关语言支持所需要的库,以下是来自官方文档的介绍:
Basic requirements
A relatively POSIX-compliant *NIX system
Cygwin or MinGW can be used on Windows
g++ 4.2
boost 1.53.0
Runtime libraries for lex and yacc might be needed for the compiler.
Requirements for building from source
GNU build tools:
autoconf 2.65
automake 1.9
libtool 1.5.24
pkg-config autoconf macros (pkg.m4)
lex and yacc (developed primarily with flex and bison)
libssl-dev
Language requirements
These are only required if you choose to build the libraries for the given language
C++
Boost 1.53.0
libevent (optional, to build the nonblocking server)
zlib (optional)
Java
Java 1.7
Apache Ant
C#: Mono 1.2.4 (and pkg-config to detect it) or Visual Studio 2005+
Python 2.6 (including header files for extension modules)
PHP 5.0 (optionally including header files for extension modules)
Ruby 1.8
bundler gem
Erlang R12 (R11 works but not recommended)
Perl 5
Bit::Vector
Class::Accessor
四、如何安装?
1) 安装依赖插件
1
root@m1:/home/hadoop#sudo apt-get install libboost-dev libboost-test-dev libboost-program-options-dev libevent-dev automake libtool flex bison pkg-config g++ libssl-dev 2) 安装最新版PHP5(因为后文会使用PHP来测试客户端与Golang服务端的交互)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#先添加phpkeyroot@m2:/home/hadoop/thrift-git# add-apt-repository ppa:ondrej/php5You are about to add the following PPA to your system:This branch follows latest PHP packages as maintained by me & rest of the Debian pkg-php team.You can get more information about the packages at https://sury.orgIf you need to stay with PHP 5.4 you can use the oldstable PHP repository:ppa:ondrej/php5-oldstableBUGS&FEATURES: This PPA now has a issue tracker: https://deb.sury.org/pages/bugreporting.htmlPLEASE READ: If you like my work and want to give me a little motivation, please consider donating: https://deb.sury.org/pages/donate.htmlMore info: https://launchpad.net/~ondrej/+archive/ubuntu/php5Press [ENTER] to continue or ctrl-c to cancel adding itgpg: 钥匙环‘/tmp/tmpZ7PZIy/secring.gpg’已建立gpg: 钥匙环‘/tmp/tmpZ7PZIy/pubring.gpg’已建立gpg: 下载密钥‘E5267A6C’,从 hkp 服务器 keyserver.ubuntu.comgpg: /tmp/tmpZ7PZIy/trustdb.gpg:建立了信任度数据库gpg: 密钥 E5267A6C:公钥"Launchpad PPA for Ondřej Surý"已导入gpg: 合计被处理的数量:1gpg: 已导入:1 (RSA: 1)OKroot@m2:/home/hadoop/thrift-git# apt-get updateroot@m1:/home/hadoop/thrift-git# apt-get install php5-dev php5-cli phpunit 3) 下载thirft0.9.1版本
1
2
3
4
5
6
7
8
9
10
11
root@m2:/home/hadoop# git clone https://github.com/apache/thrift.git thrift-gitCloning into 'thrift-git'...remote: Counting objects: 37193, done.remote: Compressing objects: 100% (216/216), done.remote: Total 37193 (delta 319), reused 407 (delta 272)Receiving objects: 100% (37193/37193), 9.62 MiB | 50 KiB/s, done.Resolving deltas: 100% (25794/25794), done.root@m1:/home/hadoop#cd thrift-gitroot@m2:/home/hadoop/thrift-git# git checkout -b 0.9.1Switched to a new branch '0.9.1' 4) 编译安装
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
root@m1:/home/hadoop/thrift-git#./bootstrap.shroot@m1:/home/hadoop/thrift-git# ./configure --enable-thrift_protocol#下面是截取部分运行成功后的信息thrift 0.9.1Building C++ Library ......... : yesBuilding C (GLib) Library .... : yesBuilding Java Library ........ : noBuilding C# Library .......... : noBuilding Python Library ...... : yesBuilding Ruby Library ........ : noBuilding Haskell Library ..... : noBuilding Perl Library ........ : noBuilding PHP Library ......... : yesBuilding Erlang Library ...... : noBuilding Go Library .......... : noBuilding D Library ........... : noC++ Library:Build TZlibTransport ...... : yesBuild TNonblockingServer .. : yesBuild TQTcpServer (Qt) .... : noPython Library:Using Python .............. : /usr/bin/pythonPHP Library:Using php-config .......... : /usr/bin/php-configIf something is missing that you think should be present,please skim the output of configure to find the missingcomponent. Details are present in config.log. 如果在安装Thrift时,不需要支持的扩展,可以在使用./configure的时候带上以下参数
1
./configure --without-php --without-ruby --without-haskell --without-python --without-perl 继续安装这个时间会长一点
1
2
root@m2:/home/hadoop/thrift-git# makeroot@m2:/home/hadoop/thrift-git# make install 我们可以看到thrift已经安装完成,当前版本是0.9.1
1
2
root@m1:/home/hadoop/thrift-git# thrift -versionThrift version 0.9.1 五、Golang、Java、Python、PHP之间通过Thrift实现跨语言调用
在写代码之前,我们先来配置Thrift的协议库IDL文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
root@m1:/home/hadoop/thrift-git/tutorial# vi idoall.org.thrift namespace go idoall.org.demonamespace java idoall.org.demonamespace php idoall.org.demonamespace py idoall.org.demostruct Student{1: i32 sid, 2: string sname,3: bool ssex=0,4: i16 sage,}const map<string,string> MAPCONSTANT = {'hello':'world', 'goodnight':'moon'}service idoallThrift { list<string> CallBack(1:i64 callTime, 2:string name, 3:map<string, string> paramMap),void put(1: Student s),} 编译IDL文件,生成相关代码
1
2
3
4
root@m1:/home/hadoop/thrift-git/tutorial# thrift -r --gen go idoall.org.thrift root@m1:/home/hadoop/thrift-git/tutorial# thrift -r --gen py idoall.org.thrift root@m1:/home/hadoop/thrift-git/tutorial# thrift -r --gen php idoall.org.thrift root@m1:/home/hadoop/thrift-git/tutorial# thrift -r --gen java idoall.org.thrift 如果编译IDL的PHP包要生成server端代码,和其他语言不太一样,可以使用thrift --help查看使用说明,需要加上server选项,如下:
1
root@m1:/home/hadoop/thrift-git/tutorial# thrift -r --gen php:server idoall.org.thrift 1) Golang 客户端和服务端的实现及交互
Golang1.3的安装,请参考这篇文章《ubuntu12.04 64bit基于源码安装golang1.3》,默认使用apt-get安装不是最新版。
#安装golang的Thrift包:
1
root@m1:/home/hadoop/thrift-git/tutorial# go get git.apache.org/thrift.git/lib/go/thrift#将Thrift生成的开发库也复制到GOPATH中
1
root@m1:/home/hadoop/thrift-git/tutorial# cp -r /home/hadoop/thrift-git/tutorial/gen-go/idoall $GOPATH/src#编写go server端代码(后面的代码,我们都放在/home/hadoop/thrift_demo目录中进行演示)
1
2
3
root@m1:/home/hadoop# mkdir thrift_demoroot@m1:/home/hadoop# cd thrift_demo/root@m1:/home/hadoop/thrift_demo# vi s.go1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
package mainimport ("idoall/org/demo""fmt""git.apache.org/thrift.git/lib/go/thrift""os")const (NetworkAddr = "0.0.0.0:10086")type idoallThrift struct {}func (this *idoallThrift) CallBack(callTime int64, name string, paramMap map[string]string) (r []string, err error) {fmt.Println("-->from client Call:", callTime, name, paramMap)r = append(r, "key:"+paramMap["a"]+" value:"+paramMap["b"])return}func (this *idoallThrift) Put(s *demo.Student) (err error){fmt.Printf("Stduent--->id: %d\tname:%s\tsex:%t\tage:%d\n", s.Sid, s.Sname, s.Ssex, s.Sage)return nil}func main() {transportFactory := thrift.NewTFramedTransportFactory(thrift.NewTTransportFactory())protocolFactory := thrift.NewTBinaryProtocolFactoryDefault()//protocolFactory := thrift.NewTCompactProtocolFactory()serverTransport, err := thrift.NewTServerSocket(NetworkAddr)if err != nil {fmt.Println("Error!", err)os.Exit(1)}handler := &idoallThrift{}processor := demo.NewIdoallThriftProcessor(handler)server := thrift.NewTSimpleServer4(processor, serverTransport, transportFactory, protocolFactory)fmt.Println("thrift server in", NetworkAddr)server.Serve()}#编写go client端代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
root@m1:/home/hadoop/thrift_demo# vi c.gopackage mainimport ("idoall/org/demo""fmt""git.apache.org/thrift.git/lib/go/thrift""net""os""time""strconv")const (HOST = "127.0.0.1"PORT = "10086")func main() {startTime := currentTimeMillis()transportFactory := thrift.NewTFramedTransportFactory(thrift.NewTTransportFactory())protocolFactory := thrift.NewTBinaryProtocolFactoryDefault()transport, err := thrift.NewTSocket(net.JoinHostPort(HOST, PORT))if err != nil {fmt.Fprintln(os.Stderr, "error resolving address:", err)os.Exit(1)}useTransport := transportFactory.GetTransport(transport)client := demo.NewIdoallThriftClientFactory(useTransport, protocolFactory)if err := transport.Open(); err != nil {fmt.Fprintln(os.Stderr, "Error opening socket to "+HOST+":"+PORT, " ", err)os.Exit(1)}defer transport.Close()for i := 0; i < 5; i++ {paramMap := make(map[string]string)paramMap["a"] = "idoall"paramMap["b"] = "org"+strconv.Itoa(i+1)r1, _ := client.CallBack(time.Now().UnixNano() / 1000000, "go client", paramMap)fmt.Println("GOClient Call->", r1)}model := demo.Student{11,"student-idoall-go",true,20}client.Put(&model)endTime := currentTimeMillis()fmt.Printf( "本次调用用时:%d-%d=%d毫秒\n",endTime,startTime, (endTime - startTime))}func currentTimeMillis() int64 {return time.Now().UnixNano() / 1000000}#运行go服务端(可以看到服务端已经在监听本机的10086端口)
1
2
root@m1:/home/hadoop/thrift_demo# go run s.gothrift server in 0.0.0.0:10086#运行go客户端
1
2
3
4
5
6
7
8
root@m1:/home/hadoop/thrift_demo# go run c.goGOClient Call-> [key:idoall value:org1]GOClient Call-> [key:idoall value:org2]GOClient Call-> [key:idoall value:org3]GOClient Call-> [key:idoall value:org4]GOClient Call-> [key:idoall value:org5]本次调用用时:1408267333489-ひく1408267333486=わ3毫秒root@m1:/home/hadoop/thrift_demo##查看go服务端,可以看到数据的交互
1
2
3
4
5
6
7
8
root@m1:/home/hadoop/thrift_demo# go run s.gothrift server in 0.0.0.0:10086-->from client Call: 1408267333487 go client map[a:idoall b:org1]-->from client Call: 1408267333487 go client map[a:idoall b:org2]-->from client Call: 1408267333488 go client map[b:org3 a:idoall]-->from client Call: 1408267333488 go client map[a:idoall b:org4]-->from client Call: 1408267333488 go client map[a:idoall b:org5]Stduent--->id: 11 name:student-idoall-go sex:true age:20 2) python 客户端的实现与golang 服务端的交互
#将python用到的Thrift包复制到thrift_demo里面
1
2
root@m1:/home/hadoop/thrift_demo# cp -r /home/hadoop/thrift-git/lib/py/build /home/hadoop/thrift_demo/libpyroot@m1:/home/hadoop/thrift_demo# cp -r /home/hadoop/thrift-git/tutorial/gen-py /home/hadoop/thrift_demo/gen-py#编写python client代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
root@m1:/home/hadoop/thrift_demo# vi c.py#!/usr/bin/env python# -*- coding: utf-8 -*-import sys, glob, time,datetimesys.path.append('gen-py')sys.path.insert(0, glob.glob('libpy/lib.*')[0])from idoall.org.demo import idoallThriftfrom idoall.org.demo.ttypes import *from thrift import Thriftfrom thrift.transport import TSocketfrom thrift.transport import TTransportfrom thrift.protocol import TBinaryProtocoltry:startTime = time.time()*1000# Make sockettransport = TSocket.TSocket('127.0.0.1', 10086)# Framed is critical. Raw sockets are very slowtransport = TTransport.TFramedTransport(transport)# Wrap in a protocolprotocol = TBinaryProtocol.TBinaryProtocol(transport)# Create a client to use the protocol encoderclient = idoallThrift.Client(protocol)# Connect!transport.open()for i in range(1,6):r = client.CallBack(time.time()*1000,"python client",{"a":"idoall","b":"org"+str(i)})print "PythonClient Call->%s" %(r)u1 = Student() u1.sid=111 u1.sname='student-idoall-python' u1.ssex=Falseu1.sage=200client.put(u1)endTime = time.time()*1000print "本次调用用时:%d-%d=%d毫秒" %(endTime,startTime, (endTime - startTime))# Close!transport.close()except Thrift.TException, tx:print 'ERROR:%s' % (tx.message)#运行go服务端
1
2
root@m1:/home/hadoop/thrift_demo# go run s.gothrift server in 0.0.0.0:10086#运行python客户端
1
2
3
4
5
6
7
8
root@m1:/home/hadoop/thrift_demo# python c.py PythonClient Call->['key:idoall value:org1']PythonClient Call->['key:idoall value:org2']PythonClient Call->['key:idoall value:org3']PythonClient Call->['key:idoall value:org4']PythonClient Call->['key:idoall value:org5']本次调用用时:1408268651648-ひく1408268651646=わ2毫秒root@m1:/home/hadoop/thrift_demo##查看go服务端,可以看到数据的交互
1
2
3
4
5
6
7
8
root@m1:/home/hadoop/thrift_demo# go run s.gothrift server in 0.0.0.0:10086-->from client Call: 1408268651646 python client map[b:org1 a:idoall]-->from client Call: 1408268651646 python client map[a:idoall b:org2]-->from client Call: 1408268651647 python client map[a:idoall b:org3]-->from client Call: 1408268651647 python client map[a:idoall b:org4]-->from client Call: 1408268651647 python client map[a:idoall b:org5]Stduent--->id: 111 name:student-idoall-python sex:false age:200 3) php 客户端的实现与golang 服务端的交互
#编译php的Thrift扩展
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
root@m1:/home/hadoop/thrift_demo# cd /home/hadoop/thrift-git/lib/php/src/ext/thrift_protocol root@m1:/home/hadoop/thrift-git/lib/php/src/ext/thrift_protocol# lsacinclude.m4 build config.h.in config.nice configure include ltmain.sh Makefile.global mkinstalldirs php_thrift_protocol.h thrift_protocol.laaclocal.m4 config.guess config.log config.status configure.in install-sh Makefile Makefile.objects modules php_thrift_protocol.loautom4te.cache config.h config.m4 config.sub config.w32 libtool Makefile.fragments missing php_thrift_protocol.cpp run-tests.phproot@m1:/home/hadoop/thrift-git/lib/php/src/ext/thrift_protocol# phpizeConfiguring for:PHP Api Version: 20121113Zend Module Api No: 20121212Zend Extension Api No: 220121212root@m1:/home/hadoop/thrift-git/lib/php/src/ext/thrift_protocol# ./configure##以下只给出部分输出信息checking for grep that handles long lines and -e... /bin/grepchecking for egrep... /bin/grep -Echecking for a sed that does not truncate output... /bin/sedchecking for cc... cc......config.status: creating config.hconfig.status: config.h is unchangedconfig.status: executing libtool commands#执行make命令后,我们可以看到扩展文件放到了/usr/lib/php5/20121212/目录root@m1:/home/hadoop/thrift-git/lib/php/src/ext/thrift_protocol# make && make installBuild complete.Don't forget to run 'make test'.Installing shared extensions: /usr/lib/php5/20121212/#让PHP支持thrift,编辑php.ini文件,搜索extension_dir,然后在下面加上extension=thrift_protocol.so,保存退出。
1
2
3
4
5
6
7
root@m1:/home/hadoop/thrift-git/lib/php/src/ext/thrift_protocol# vi /etc/php5/fpm/php.ini; Directory in which the loadable extensions (modules) reside.; http://php.net/extension-dir; extension_dir = "./"; On windows:; extension_dir = "ext"extension=thrift_protocol.so#重启php5-fpm
1
2
3
4
root@m1:/home/hadoop/thrift-git/lib/php/src/ext/thrift_protocol# service php5-fpm restartphp5-fpm stop/waitingphp5-fpm start/running, process 16522root@m1:/home/hadoop/thrift-git/lib/php/src/ext/thrift_protocol##将php用到的Thrift包复制到thrift_demo里面
1
2
3
4
5
root@m1:/home/hadoop/thrift-git/lib/php/src/ext/thrift_protocol# mkdir -p /home/hadoop/thrift_demo/libphp/root@m1:/home/hadoop/thrift-git/lib/php/src/ext/thrift_protocol# cp -r /home/hadoop/thrift-git/lib/php/src/* /home/hadoop/thrift_demo/libphp/root@m1:/home/hadoop/thrift-git/lib/php/src/ext/thrift_protocol# cp -r /home/hadoop/thrift-git/lib/php/lib/Thrift /home/hadoop/thrift_demo/libphproot@m1:/home/hadoop/thrift-git/lib/php/src/ext/thrift_protocol# cp -r /home/hadoop/thrift-git/tutorial/gen-php /home/hadoop/thrift_demo/gen-phproot@m1:/home/hadoop/thrift-git/lib/php/src/ext/thrift_protocol# cd /home/hadoop/thrift_demo#编写php client端代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
root@m1:/home/hadoop/thrift_demo# vi c.php<?php $startTime = getMillisecond();$GLOBALS['THRIFT_ROOT'] = './libphp'; # 指定库目录,可以是绝对路径或是相对路径 require_once $GLOBALS['THRIFT_ROOT'].'/Thrift/ClassLoader/ThriftClassLoader.php';use Thrift\ClassLoader\ThriftClassLoader; use Thrift\Protocol\TBinaryProtocol; use Thrift\Transport\TSocket; use Thrift\Transport\TSocketPool; use Thrift\Transport\TFramedTransport; use Thrift\Transport\TBufferedTransport;$GEN_DIR = realpath(dirname(__FILE__)).'/gen-php';$loader = new ThriftClassLoader(); $loader->registerNamespace('Thrift', $GLOBALS['THRIFT_ROOT']); # 加载thrift $loader->registerDefinition('idoall\org\demo', $GEN_DIR); # 加载自己写的thrift文件编译的类文件和数据定义 $loader->register();$socket = new TSocket('127.0.0.1', 10086); # 建立socket $socket->setDebug(TRUE); $framedSocket = new TFramedTransport($socket); #这个要和服务器使用的一致 $transport = $framedSocket; $protocol = new TBinaryProtocol($transport); # 这里也要和服务器使用的协议一致 $transport->open();$client= new \idoall\org\demo\idoallThriftClient($protocol); # 构造客户端for($i=1;$i<6;$i++){$item = array();$item["a"] = "idoall";$item["b"] = "org"+$i;$result = $client->CallBack(getMillisecond(),"php client",$item); # 对服务器发起rpc调用 echo "PHPClient Call->".implode('',$result)."\n";}$s = new \idoall\org\demo\Student();$s->sid=1111;$s->sname="student-idoall-php";$s->ssex = false;$s->sage = 2000;$client->put($s);$endTime = getMillisecond();echo "本次调用用时:".$endTime."-".$startTime."=".($endTime-$startTime)."毫秒\n";function getMillisecond() {list($t1, $t2) = explode(' ', microtime()); return (float)sprintf('%.0f', (floatval($t1) + floatval($t2)) * 1000); }$transport->close(); # 关闭链接#运行go服务端
1
2
root@m1:/home/hadoop/thrift_demo# go run s.gothrift server in 0.0.0.0:10086#运行php客户端
1
2
3
4
5
6
7
root@m1:/home/hadoop/thrift_demo# php c.php PHPClient Call->key:idoall value:1PHPClient Call->key:idoall value:2PHPClient Call->key:idoall value:3PHPClient Call->key:idoall value:4PHPClient Call->key:idoall value:5本次调用用时:1408268739277-ひく1408268739269=わ8毫秒#查看go服务端,可以看到数据的交互
1
2
3
4
5
6
7
8
root@m1:/home/hadoop/thrift_demo# go run s.gothrift server in 0.0.0.0:10086-->from client Call: 1408268739272 php client map[a:idoall b:1]-->from client Call: 1408268739273 php client map[a:idoall b:2]-->from client Call: 1408268739274 php client map[a:idoall b:3]-->from client Call: 1408268739275 php client map[a:idoall b:4]-->from client Call: 1408268739275 php client map[a:idoall b:5]Stduent--->id: 1111 name:student-idoall-php sex:false age:2000 4) java 客户端的实现与golang 服务端的交互
#安装maven项目管理工具
1
root@m1:/home/hadoop/thrift_demo# apt-get install maven#将java用到的Thrift包复制到thrift_demo里面
1
2
3
4
5
6
root@m1:/home/hadoop/thrift_demo# cp -r /home/hadoop/thrift-git/tutorial/gen-java .root@m1:/home/hadoop/thrift_demo# cd gen-javaroot@m1:/home/hadoop/thrift_demo/gen-java# mkdir -p src/main/javaroot@m1:/home/hadoop/thrift_demo/gen-java# mkdir META-INFroot@m1:/home/hadoop/thrift_demo/gen-java# mkdir libroot@m1:/home/hadoop/thrift_demo/gen-java# cp -r /home/hadoop/thrift-git/lib/java/build/libthrift-0.9.1.jar ./lib/#编写java client端代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
root@m1:/home/hadoop/thrift_demo/gen-java# vi idoall/org/demo/c.javapackage idoall.org.demo;import java.util.HashMap;import java.util.List;import java.util.Map;import org.apache.thrift.TException;import org.apache.thrift.protocol.TBinaryProtocol;import org.apache.thrift.protocol.TProtocol;import org.apache.thrift.transport.TFramedTransport;import org.apache.thrift.transport.TSocket;import org.apache.thrift.transport.TTransport;import org.apache.thrift.transport.TTransportException;public class c {public static final String SERVER_IP = "m1";public static final int SERVER_PORT = 10086;public static final int TIMEOUT = 30000;/*** @param args*/public static void main(String[] args) {long startTime=System.currentTimeMillis(); //获取开始时间TTransport transport = null;try {transport = new TFramedTransport(new TSocket(SERVER_IP,SERVER_PORT, TIMEOUT));// 协议要和服务端一致TProtocol protocol = new TBinaryProtocol(transport);idoallThrift.Client client = new idoallThrift.Client(protocol);transport.open();for(int i=1;i<6;i++){Map<String,String> m = new HashMap<String,String>();m.put("a", "idoall");m.put("b", "org"+i);List<String> result = client.CallBack(System.currentTimeMillis(),"java client",m);System.out.println("JAVAClient Call->" + result);}Student s = new Student();s.sid=1111;s.sname="student-idoall-java";s.ssex = true;s.sage = 20000;client.put(s);long endTime = System.currentTimeMillis();System.out.println("本次调用用时:" + endTime + "-" + startTime + "=" + (endTime - startTime)+"毫秒");} catch (TTransportException e) {e.printStackTrace();} catch (TException e) {e.printStackTrace();} finally {if (null != transport) {transport.close();}}}}#配置jar包的MANIFEST文件
1
2
3
4
root@m1:/home/hadoop/thrift_demo/gen-java# vi META-INF/MANIFEST.MFManifest-Version: 1.0Main-Class: idoall.org.demo.cClass-Path: lib/**.jar#制作Maven的描述文件pom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
root@m1:/home/hadoop/thrift_demo/gen-java# vi pom.xml<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>idoall.org.demo</groupId><artifactId>idoall.org.demo</artifactId><version>0.0.1-SNAPSHOT</version><packaging>jar</packaging><name>idoall.org.demo</name><url>http://maven.apache.org</url><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>3.8.1</version><scope>test</scope></dependency><dependency><groupId>org.apache.thrift</groupId><artifactId>libthrift</artifactId><version>0.9.1</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>1.5.8</version></dependency></dependencies><build><plugins><plugin><artifactId>maven-assembly-plugin</artifactId><configuration><archive><manifest><mainClass>idoall.org.demo.c</mainClass></manifest></archive><descriptorRefs><descriptorRef>jar-with-dependencies</descriptorRef></descriptorRefs></configuration></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><source>1.6</source><target>1.6</target></configuration></plugin></plugins></build></project>#使用maven工具,将相关依赖打包到当前目录的target目录中,并生成idoall.org.demo-0.0.1-SNAPSHOT-jar-with-dependencies.jar
1
2
3
4
5
6
7
8
9
10
root@m1:/home/hadoop/thrift_demo/gen-java# mv idoall src/main/java/root@m1:/home/hadoop/thrift_demo/gen-java# mvn assembly:assembly#以下只给出部分提示信息[INFO] ------------------------------------------------------------------------[INFO] BUILD SUCCESS[INFO] ------------------------------------------------------------------------[INFO] Total time: 7.618s[INFO] Finished at: Sun Aug 17 09:36:48 CST 2014[INFO] Final Memory: 12M/29M[INFO] ------------------------------------------------------------------------#运行go服务端
1
2
root@m1:/home/hadoop/thrift_demo# go run s.gothrift server in 0.0.0.0:10086#运行打包后的java客户端
1
2
3
4
5
6
7
root@m1:/home/hadoop/thrift_demo/gen-java# java -jar target/idoall.org.demo-0.0.1-SNAPSHOT-jar-with-dependencies.jar JAVAClient Call->[key:idoall value:org1]JAVAClient Call->[key:idoall value:org2]JAVAClient Call->[key:idoall value:org3]JAVAClient Call->[key:idoall value:org4]JAVAClient Call->[key:idoall value:org5]本次调用用时:1408268973582-ひく1408268973477=わ105毫秒#查看go服务端,可以看到数据的交互
1
2
3
4
5
6
7
8
root@m1:/home/hadoop/thrift_demo# go run s.gothrift server in 0.0.0.0:10086-->from client Call: 1408268973547 java client map[a:idoall b:org1]-->from client Call: 1408268973568 java client map[b:org2 a:idoall]-->from client Call: 1408268973568 java client map[b:org3 a:idoall]-->from client Call: 1408268973568 java client map[b:org4 a:idoall]-->from client Call: 1408268973569 java client map[b:org5 a:idoall]Stduent--->id: 1111 name:student-idoall-java sex:true age:20000 六、扩展阅读
文章中使用的代码提供下载,在这里:http://pan.baidu.com/s/1dDF1rRr
---------------------------------------
博文作者:迦壹
转载声明:可以转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明,谢谢合作!
---------------------------------------
有疑问加站长微信联系(非本文作者)
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
关注微信3994 次点击
添加一条新回复
(您需要 后才能回复 没有账号 ?)
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码` - 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传
收入到我管理的专栏 新建专栏
目录:
一、什么是Thrift?
1) Thrift内部框架一瞥
2) 支持的数据传输格式、数据传输方式和服务模型
3) Thrift IDL
二、Thrift的官方网站在哪里?
三、在哪里下载?需要哪些组件的支持?
四、如何安装?
五、Golang、Java、Python、PHP之间通过Thrift实现跨语言调用
1) Golang 客户端和服务端的实现及交互
2) python 客户端的实现与golang 服务端的交互
3) php 客户端的实现与golang 服务端的交互
4) java 客户端的实现与golang 服务端的交互
六、扩展阅读
一、什么是Thrift
Thrift是一种可伸缩的跨语言服务的发展软件框架。它结合了功能强大的软件堆栈的代码生成引擎,以建设服务。
Thrift是facebook开发的,07年4月开放源代码,08年5月进入apache孵化器。创造Thrift是为了解决facebook系统中各系统间大数据量的传 输通信以及系统之间语言环境不同需要跨平台的特性。所以thrift可以支持多种程序语言,例如: C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, and OCaml. (目前0.9.1版本已经开始支持golang语言)在多种不同的语言之间通信thrift可以作为二进制的高性能的通讯中间件,支持数据(对象)序列化和多种类型的RPC服务。
Thrift允许你定义一个简单的定义文件中的数据类型和服务接口。以作为输入文件,编译器生成代码用来方便地生成RPC客户端和服务器通信的无缝跨编程语言。简而言之,开发者只需准备一份thrift脚本,通过thrift code generator(像gcc那样输入一个命令)就能生成所要求的开发语言代码。
类似Thrift的工具,还有Avro、protocol buffer,但相对于Thrift来讲,都没有Thrift支持全面和使用广泛。
1) thrift内部框架一瞥
按照官方文档给出的整体框架,Thrift自下到上可以分为4层:
+-------------------------------------------+
| Server | -- 服务器进程调度
| (single-threaded, event-driven etc) |
+-------------------------------------------+
| Processor | -- RPC接口处理函数分发,IDL定义接口的实现将挂接到这里面
| (compiler generated) |
+-------------------------------------------+
| Protocol | -- 协议
| (JSON, compact etc) |
+-------------------------------------------+
| Transport | -- 网络传输
| (raw TCP, HTTP etc) |
+-------------------------------------------+
Thrift实际上是实现了C/S模式,通过代码生成工具将接口定义文件生成服务器端和客户端代码(可以为不同语言),从而实现服务端和客户端跨语言的支持。用户在Thirft描述文件中声明自己的服务,这些服务经过编译后会生成相应语言的代码文件,然后用户实现服务(客户端调用服务,服务器端提服务)便可以了。其中protocol(协议层, 定义数据传输格式,可以为二进制或者XML等)和transport(传输层,定义数据传输方式,可以为TCP/IP传输,内存共享或者文件共享等)被用作运行时库。
2)支持的数据传输格式、数据传输方式和服务模型
(a)支持的传输格式
TBinaryProtocol – 二进制格式.
TCompactProtocol – 压缩格式
TJSONProtocol – JSON格式
TSimpleJSONProtocol –提供JSON只写协议, 生成的文件很容易通过脚本语言解析。
TDebugProtocol – 使用易懂的可读的文本格式,以便于debug
(b) 支持的数据传输方式
TSocket -阻塞式socker
TFramedTransport – 以frame为单位进行传输,非阻塞式服务中使用。
TFileTransport – 以文件形式进行传输。
TMemoryTransport – 将内存用于I/O. java实现时内部实际使用了简单的ByteArrayOutputStream。
TZlibTransport – 使用zlib进行压缩, 与其他传输方式联合使用。当前无java实现。
(c)支持的服务模型
TSimpleServer – 简单的单线程服务模型,常用于测试
TThreadPoolServer – 多线程服务模型,使用标准的阻塞式IO。
TNonblockingServer – 多线程服务模型,使用非阻塞式IO(需使用TFramedTransport数据传输方式)
3) Thrift IDL
Thrift定义一套IDL(Interface Definition Language)用于描述接口,通常后缀名为.thrift,通过thrift程序把.thrift文件导出成各种不一样的代码的协议定义。IDL支持的类型可以参考这里:http://thrift.apache.org/docs/types
二、Thrift的官方网站在哪里?
三、在哪里下载?需要哪些组件的支持?
Thrift的官方下载地址在这里:http://www.apache.org/dyn/closer.cgi?path=/thrift/0.9.1/thrift-0.9.1.tar.gz
(现在官网打包后的0.9.1版本在make的时候会出各种问题,后文会介绍不建议使用官网提供的0.9.1包)
Thrift的安装依赖,以及相关语言支持所需要的库,以下是来自官方文档的介绍:
Basic requirements
A relatively POSIX-compliant *NIX system
Cygwin or MinGW can be used on Windows
g++ 4.2
boost 1.53.0
Runtime libraries for lex and yacc might be needed for the compiler.
Requirements for building from source
GNU build tools:
autoconf 2.65
automake 1.9
libtool 1.5.24
pkg-config autoconf macros (pkg.m4)
lex and yacc (developed primarily with flex and bison)
libssl-dev
Language requirements
These are only required if you choose to build the libraries for the given language
C++
Boost 1.53.0
libevent (optional, to build the nonblocking server)
zlib (optional)
Java
Java 1.7
Apache Ant
C#: Mono 1.2.4 (and pkg-config to detect it) or Visual Studio 2005+
Python 2.6 (including header files for extension modules)
PHP 5.0 (optionally including header files for extension modules)
Ruby 1.8
bundler gem
Erlang R12 (R11 works but not recommended)
Perl 5
Bit::Vector
Class::Accessor
四、如何安装?
1) 安装依赖插件
1
root@m1:/home/hadoop#sudo apt-get install libboost-dev libboost-test-dev libboost-program-options-dev libevent-dev automake libtool flex bison pkg-config g++ libssl-dev 2) 安装最新版PHP5(因为后文会使用PHP来测试客户端与Golang服务端的交互)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#先添加phpkeyroot@m2:/home/hadoop/thrift-git# add-apt-repository ppa:ondrej/php5You are about to add the following PPA to your system:This branch follows latest PHP packages as maintained by me & rest of the Debian pkg-php team.You can get more information about the packages at https://sury.orgIf you need to stay with PHP 5.4 you can use the oldstable PHP repository:ppa:ondrej/php5-oldstableBUGS&FEATURES: This PPA now has a issue tracker: https://deb.sury.org/pages/bugreporting.htmlPLEASE READ: If you like my work and want to give me a little motivation, please consider donating: https://deb.sury.org/pages/donate.htmlMore info: https://launchpad.net/~ondrej/+archive/ubuntu/php5Press [ENTER] to continue or ctrl-c to cancel adding itgpg: 钥匙环‘/tmp/tmpZ7PZIy/secring.gpg’已建立gpg: 钥匙环‘/tmp/tmpZ7PZIy/pubring.gpg’已建立gpg: 下载密钥‘E5267A6C’,从 hkp 服务器 keyserver.ubuntu.comgpg: /tmp/tmpZ7PZIy/trustdb.gpg:建立了信任度数据库gpg: 密钥 E5267A6C:公钥"Launchpad PPA for Ondřej Surý"已导入gpg: 合计被处理的数量:1gpg: 已导入:1 (RSA: 1)OKroot@m2:/home/hadoop/thrift-git# apt-get updateroot@m1:/home/hadoop/thrift-git# apt-get install php5-dev php5-cli phpunit 3) 下载thirft0.9.1版本
1
2
3
4
5
6
7
8
9
10
11
root@m2:/home/hadoop# git clone https://github.com/apache/thrift.git thrift-gitCloning into 'thrift-git'...remote: Counting objects: 37193, done.remote: Compressing objects: 100% (216/216), done.remote: Total 37193 (delta 319), reused 407 (delta 272)Receiving objects: 100% (37193/37193), 9.62 MiB | 50 KiB/s, done.Resolving deltas: 100% (25794/25794), done.root@m1:/home/hadoop#cd thrift-gitroot@m2:/home/hadoop/thrift-git# git checkout -b 0.9.1Switched to a new branch '0.9.1' 4) 编译安装
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
root@m1:/home/hadoop/thrift-git#./bootstrap.shroot@m1:/home/hadoop/thrift-git# ./configure --enable-thrift_protocol#下面是截取部分运行成功后的信息thrift 0.9.1Building C++ Library ......... : yesBuilding C (GLib) Library .... : yesBuilding Java Library ........ : noBuilding C# Library .......... : noBuilding Python Library ...... : yesBuilding Ruby Library ........ : noBuilding Haskell Library ..... : noBuilding Perl Library ........ : noBuilding PHP Library ......... : yesBuilding Erlang Library ...... : noBuilding Go Library .......... : noBuilding D Library ........... : noC++ Library:Build TZlibTransport ...... : yesBuild TNonblockingServer .. : yesBuild TQTcpServer (Qt) .... : noPython Library:Using Python .............. : /usr/bin/pythonPHP Library:Using php-config .......... : /usr/bin/php-configIf something is missing that you think should be present,please skim the output of configure to find the missingcomponent. Details are present in config.log. 如果在安装Thrift时,不需要支持的扩展,可以在使用./configure的时候带上以下参数
1
./configure --without-php --without-ruby --without-haskell --without-python --without-perl 继续安装这个时间会长一点
1
2
root@m2:/home/hadoop/thrift-git# makeroot@m2:/home/hadoop/thrift-git# make install 我们可以看到thrift已经安装完成,当前版本是0.9.1
1
2
root@m1:/home/hadoop/thrift-git# thrift -versionThrift version 0.9.1 五、Golang、Java、Python、PHP之间通过Thrift实现跨语言调用
在写代码之前,我们先来配置Thrift的协议库IDL文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
root@m1:/home/hadoop/thrift-git/tutorial# vi idoall.org.thrift namespace go idoall.org.demonamespace java idoall.org.demonamespace php idoall.org.demonamespace py idoall.org.demostruct Student{1: i32 sid, 2: string sname,3: bool ssex=0,4: i16 sage,}const map<string,string> MAPCONSTANT = {'hello':'world', 'goodnight':'moon'}service idoallThrift { list<string> CallBack(1:i64 callTime, 2:string name, 3:map<string, string> paramMap),void put(1: Student s),} 编译IDL文件,生成相关代码
1
2
3
4
root@m1:/home/hadoop/thrift-git/tutorial# thrift -r --gen go idoall.org.thrift root@m1:/home/hadoop/thrift-git/tutorial# thrift -r --gen py idoall.org.thrift root@m1:/home/hadoop/thrift-git/tutorial# thrift -r --gen php idoall.org.thrift root@m1:/home/hadoop/thrift-git/tutorial# thrift -r --gen java idoall.org.thrift 如果编译IDL的PHP包要生成server端代码,和其他语言不太一样,可以使用thrift --help查看使用说明,需要加上server选项,如下:
1
root@m1:/home/hadoop/thrift-git/tutorial# thrift -r --gen php:server idoall.org.thrift 1) Golang 客户端和服务端的实现及交互
Golang1.3的安装,请参考这篇文章《ubuntu12.04 64bit基于源码安装golang1.3》,默认使用apt-get安装不是最新版。
#安装golang的Thrift包:
1
root@m1:/home/hadoop/thrift-git/tutorial# go get git.apache.org/thrift.git/lib/go/thrift#将Thrift生成的开发库也复制到GOPATH中
1
root@m1:/home/hadoop/thrift-git/tutorial# cp -r /home/hadoop/thrift-git/tutorial/gen-go/idoall $GOPATH/src#编写go server端代码(后面的代码,我们都放在/home/hadoop/thrift_demo目录中进行演示)
1
2
3
root@m1:/home/hadoop# mkdir thrift_demoroot@m1:/home/hadoop# cd thrift_demo/root@m1:/home/hadoop/thrift_demo# vi s.go1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
package mainimport ("idoall/org/demo""fmt""git.apache.org/thrift.git/lib/go/thrift""os")const (NetworkAddr = "0.0.0.0:10086")type idoallThrift struct {}func (this *idoallThrift) CallBack(callTime int64, name string, paramMap map[string]string) (r []string, err error) {fmt.Println("-->from client Call:", callTime, name, paramMap)r = append(r, "key:"+paramMap["a"]+" value:"+paramMap["b"])return}func (this *idoallThrift) Put(s *demo.Student) (err error){fmt.Printf("Stduent--->id: %d\tname:%s\tsex:%t\tage:%d\n", s.Sid, s.Sname, s.Ssex, s.Sage)return nil}func main() {transportFactory := thrift.NewTFramedTransportFactory(thrift.NewTTransportFactory())protocolFactory := thrift.NewTBinaryProtocolFactoryDefault()//protocolFactory := thrift.NewTCompactProtocolFactory()serverTransport, err := thrift.NewTServerSocket(NetworkAddr)if err != nil {fmt.Println("Error!", err)os.Exit(1)}handler := &idoallThrift{}processor := demo.NewIdoallThriftProcessor(handler)server := thrift.NewTSimpleServer4(processor, serverTransport, transportFactory, protocolFactory)fmt.Println("thrift server in", NetworkAddr)server.Serve()}#编写go client端代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
root@m1:/home/hadoop/thrift_demo# vi c.gopackage mainimport ("idoall/org/demo""fmt""git.apache.org/thrift.git/lib/go/thrift""net""os""time""strconv")const (HOST = "127.0.0.1"PORT = "10086")func main() {startTime := currentTimeMillis()transportFactory := thrift.NewTFramedTransportFactory(thrift.NewTTransportFactory())protocolFactory := thrift.NewTBinaryProtocolFactoryDefault()transport, err := thrift.NewTSocket(net.JoinHostPort(HOST, PORT))if err != nil {fmt.Fprintln(os.Stderr, "error resolving address:", err)os.Exit(1)}useTransport := transportFactory.GetTransport(transport)client := demo.NewIdoallThriftClientFactory(useTransport, protocolFactory)if err := transport.Open(); err != nil {fmt.Fprintln(os.Stderr, "Error opening socket to "+HOST+":"+PORT, " ", err)os.Exit(1)}defer transport.Close()for i := 0; i < 5; i++ {paramMap := make(map[string]string)paramMap["a"] = "idoall"paramMap["b"] = "org"+strconv.Itoa(i+1)r1, _ := client.CallBack(time.Now().UnixNano() / 1000000, "go client", paramMap)fmt.Println("GOClient Call->", r1)}model := demo.Student{11,"student-idoall-go",true,20}client.Put(&model)endTime := currentTimeMillis()fmt.Printf( "本次调用用时:%d-%d=%d毫秒\n",endTime,startTime, (endTime - startTime))}func currentTimeMillis() int64 {return time.Now().UnixNano() / 1000000}#运行go服务端(可以看到服务端已经在监听本机的10086端口)
1
2
root@m1:/home/hadoop/thrift_demo# go run s.gothrift server in 0.0.0.0:10086#运行go客户端
1
2
3
4
5
6
7
8
root@m1:/home/hadoop/thrift_demo# go run c.goGOClient Call-> [key:idoall value:org1]GOClient Call-> [key:idoall value:org2]GOClient Call-> [key:idoall value:org3]GOClient Call-> [key:idoall value:org4]GOClient Call-> [key:idoall value:org5]本次调用用时:1408267333489-ひく1408267333486=わ3毫秒root@m1:/home/hadoop/thrift_demo##查看go服务端,可以看到数据的交互
1
2
3
4
5
6
7
8
root@m1:/home/hadoop/thrift_demo# go run s.gothrift server in 0.0.0.0:10086-->from client Call: 1408267333487 go client map[a:idoall b:org1]-->from client Call: 1408267333487 go client map[a:idoall b:org2]-->from client Call: 1408267333488 go client map[b:org3 a:idoall]-->from client Call: 1408267333488 go client map[a:idoall b:org4]-->from client Call: 1408267333488 go client map[a:idoall b:org5]Stduent--->id: 11 name:student-idoall-go sex:true age:20 2) python 客户端的实现与golang 服务端的交互
#将python用到的Thrift包复制到thrift_demo里面
1
2
root@m1:/home/hadoop/thrift_demo# cp -r /home/hadoop/thrift-git/lib/py/build /home/hadoop/thrift_demo/libpyroot@m1:/home/hadoop/thrift_demo# cp -r /home/hadoop/thrift-git/tutorial/gen-py /home/hadoop/thrift_demo/gen-py#编写python client代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
root@m1:/home/hadoop/thrift_demo# vi c.py#!/usr/bin/env python# -*- coding: utf-8 -*-import sys, glob, time,datetimesys.path.append('gen-py')sys.path.insert(0, glob.glob('libpy/lib.*')[0])from idoall.org.demo import idoallThriftfrom idoall.org.demo.ttypes import *from thrift import Thriftfrom thrift.transport import TSocketfrom thrift.transport import TTransportfrom thrift.protocol import TBinaryProtocoltry:startTime = time.time()*1000# Make sockettransport = TSocket.TSocket('127.0.0.1', 10086)# Framed is critical. Raw sockets are very slowtransport = TTransport.TFramedTransport(transport)# Wrap in a protocolprotocol = TBinaryProtocol.TBinaryProtocol(transport)# Create a client to use the protocol encoderclient = idoallThrift.Client(protocol)# Connect!transport.open()for i in range(1,6):r = client.CallBack(time.time()*1000,"python client",{"a":"idoall","b":"org"+str(i)})print "PythonClient Call->%s" %(r)u1 = Student() u1.sid=111 u1.sname='student-idoall-python' u1.ssex=Falseu1.sage=200client.put(u1)endTime = time.time()*1000print "本次调用用时:%d-%d=%d毫秒" %(endTime,startTime, (endTime - startTime))# Close!transport.close()except Thrift.TException, tx:print 'ERROR:%s' % (tx.message)#运行go服务端
1
2
root@m1:/home/hadoop/thrift_demo# go run s.gothrift server in 0.0.0.0:10086#运行python客户端
1
2
3
4
5
6
7
8
root@m1:/home/hadoop/thrift_demo# python c.py PythonClient Call->['key:idoall value:org1']PythonClient Call->['key:idoall value:org2']PythonClient Call->['key:idoall value:org3']PythonClient Call->['key:idoall value:org4']PythonClient Call->['key:idoall value:org5']本次调用用时:1408268651648-ひく1408268651646=わ2毫秒root@m1:/home/hadoop/thrift_demo##查看go服务端,可以看到数据的交互
1
2
3
4
5
6
7
8
root@m1:/home/hadoop/thrift_demo# go run s.gothrift server in 0.0.0.0:10086-->from client Call: 1408268651646 python client map[b:org1 a:idoall]-->from client Call: 1408268651646 python client map[a:idoall b:org2]-->from client Call: 1408268651647 python client map[a:idoall b:org3]-->from client Call: 1408268651647 python client map[a:idoall b:org4]-->from client Call: 1408268651647 python client map[a:idoall b:org5]Stduent--->id: 111 name:student-idoall-python sex:false age:200 3) php 客户端的实现与golang 服务端的交互
#编译php的Thrift扩展
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
root@m1:/home/hadoop/thrift_demo# cd /home/hadoop/thrift-git/lib/php/src/ext/thrift_protocol root@m1:/home/hadoop/thrift-git/lib/php/src/ext/thrift_protocol# lsacinclude.m4 build config.h.in config.nice configure include ltmain.sh Makefile.global mkinstalldirs php_thrift_protocol.h thrift_protocol.laaclocal.m4 config.guess config.log config.status configure.in install-sh Makefile Makefile.objects modules php_thrift_protocol.loautom4te.cache config.h config.m4 config.sub config.w32 libtool Makefile.fragments missing php_thrift_protocol.cpp run-tests.phproot@m1:/home/hadoop/thrift-git/lib/php/src/ext/thrift_protocol# phpizeConfiguring for:PHP Api Version: 20121113Zend Module Api No: 20121212Zend Extension Api No: 220121212root@m1:/home/hadoop/thrift-git/lib/php/src/ext/thrift_protocol# ./configure##以下只给出部分输出信息checking for grep that handles long lines and -e... /bin/grepchecking for egrep... /bin/grep -Echecking for a sed that does not truncate output... /bin/sedchecking for cc... cc......config.status: creating config.hconfig.status: config.h is unchangedconfig.status: executing libtool commands#执行make命令后,我们可以看到扩展文件放到了/usr/lib/php5/20121212/目录root@m1:/home/hadoop/thrift-git/lib/php/src/ext/thrift_protocol# make && make installBuild complete.Don't forget to run 'make test'.Installing shared extensions: /usr/lib/php5/20121212/#让PHP支持thrift,编辑php.ini文件,搜索extension_dir,然后在下面加上extension=thrift_protocol.so,保存退出。
1
2
3
4
5
6
7
root@m1:/home/hadoop/thrift-git/lib/php/src/ext/thrift_protocol# vi /etc/php5/fpm/php.ini; Directory in which the loadable extensions (modules) reside.; http://php.net/extension-dir; extension_dir = "./"; On windows:; extension_dir = "ext"extension=thrift_protocol.so#重启php5-fpm
1
2
3
4
root@m1:/home/hadoop/thrift-git/lib/php/src/ext/thrift_protocol# service php5-fpm restartphp5-fpm stop/waitingphp5-fpm start/running, process 16522root@m1:/home/hadoop/thrift-git/lib/php/src/ext/thrift_protocol##将php用到的Thrift包复制到thrift_demo里面
1
2
3
4
5
root@m1:/home/hadoop/thrift-git/lib/php/src/ext/thrift_protocol# mkdir -p /home/hadoop/thrift_demo/libphp/root@m1:/home/hadoop/thrift-git/lib/php/src/ext/thrift_protocol# cp -r /home/hadoop/thrift-git/lib/php/src/* /home/hadoop/thrift_demo/libphp/root@m1:/home/hadoop/thrift-git/lib/php/src/ext/thrift_protocol# cp -r /home/hadoop/thrift-git/lib/php/lib/Thrift /home/hadoop/thrift_demo/libphproot@m1:/home/hadoop/thrift-git/lib/php/src/ext/thrift_protocol# cp -r /home/hadoop/thrift-git/tutorial/gen-php /home/hadoop/thrift_demo/gen-phproot@m1:/home/hadoop/thrift-git/lib/php/src/ext/thrift_protocol# cd /home/hadoop/thrift_demo#编写php client端代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
root@m1:/home/hadoop/thrift_demo# vi c.php<?php $startTime = getMillisecond();$GLOBALS['THRIFT_ROOT'] = './libphp'; # 指定库目录,可以是绝对路径或是相对路径 require_once $GLOBALS['THRIFT_ROOT'].'/Thrift/ClassLoader/ThriftClassLoader.php';use Thrift\ClassLoader\ThriftClassLoader; use Thrift\Protocol\TBinaryProtocol; use Thrift\Transport\TSocket; use Thrift\Transport\TSocketPool; use Thrift\Transport\TFramedTransport; use Thrift\Transport\TBufferedTransport;$GEN_DIR = realpath(dirname(__FILE__)).'/gen-php';$loader = new ThriftClassLoader(); $loader->registerNamespace('Thrift', $GLOBALS['THRIFT_ROOT']); # 加载thrift $loader->registerDefinition('idoall\org\demo', $GEN_DIR); # 加载自己写的thrift文件编译的类文件和数据定义 $loader->register();$socket = new TSocket('127.0.0.1', 10086); # 建立socket $socket->setDebug(TRUE); $framedSocket = new TFramedTransport($socket); #这个要和服务器使用的一致 $transport = $framedSocket; $protocol = new TBinaryProtocol($transport); # 这里也要和服务器使用的协议一致 $transport->open();$client= new \idoall\org\demo\idoallThriftClient($protocol); # 构造客户端for($i=1;$i<6;$i++){$item = array();$item["a"] = "idoall";$item["b"] = "org"+$i;$result = $client->CallBack(getMillisecond(),"php client",$item); # 对服务器发起rpc调用 echo "PHPClient Call->".implode('',$result)."\n";}$s = new \idoall\org\demo\Student();$s->sid=1111;$s->sname="student-idoall-php";$s->ssex = false;$s->sage = 2000;$client->put($s);$endTime = getMillisecond();echo "本次调用用时:".$endTime."-".$startTime."=".($endTime-$startTime)."毫秒\n";function getMillisecond() {list($t1, $t2) = explode(' ', microtime()); return (float)sprintf('%.0f', (floatval($t1) + floatval($t2)) * 1000); }$transport->close(); # 关闭链接#运行go服务端
1
2
root@m1:/home/hadoop/thrift_demo# go run s.gothrift server in 0.0.0.0:10086#运行php客户端
1
2
3
4
5
6
7
root@m1:/home/hadoop/thrift_demo# php c.php PHPClient Call->key:idoall value:1PHPClient Call->key:idoall value:2PHPClient Call->key:idoall value:3PHPClient Call->key:idoall value:4PHPClient Call->key:idoall value:5本次调用用时:1408268739277-ひく1408268739269=わ8毫秒#查看go服务端,可以看到数据的交互
1
2
3
4
5
6
7
8
root@m1:/home/hadoop/thrift_demo# go run s.gothrift server in 0.0.0.0:10086-->from client Call: 1408268739272 php client map[a:idoall b:1]-->from client Call: 1408268739273 php client map[a:idoall b:2]-->from client Call: 1408268739274 php client map[a:idoall b:3]-->from client Call: 1408268739275 php client map[a:idoall b:4]-->from client Call: 1408268739275 php client map[a:idoall b:5]Stduent--->id: 1111 name:student-idoall-php sex:false age:2000 4) java 客户端的实现与golang 服务端的交互
#安装maven项目管理工具
1
root@m1:/home/hadoop/thrift_demo# apt-get install maven#将java用到的Thrift包复制到thrift_demo里面
1
2
3
4
5
6
root@m1:/home/hadoop/thrift_demo# cp -r /home/hadoop/thrift-git/tutorial/gen-java .root@m1:/home/hadoop/thrift_demo# cd gen-javaroot@m1:/home/hadoop/thrift_demo/gen-java# mkdir -p src/main/javaroot@m1:/home/hadoop/thrift_demo/gen-java# mkdir META-INFroot@m1:/home/hadoop/thrift_demo/gen-java# mkdir libroot@m1:/home/hadoop/thrift_demo/gen-java# cp -r /home/hadoop/thrift-git/lib/java/build/libthrift-0.9.1.jar ./lib/#编写java client端代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
root@m1:/home/hadoop/thrift_demo/gen-java# vi idoall/org/demo/c.javapackage idoall.org.demo;import java.util.HashMap;import java.util.List;import java.util.Map;import org.apache.thrift.TException;import org.apache.thrift.protocol.TBinaryProtocol;import org.apache.thrift.protocol.TProtocol;import org.apache.thrift.transport.TFramedTransport;import org.apache.thrift.transport.TSocket;import org.apache.thrift.transport.TTransport;import org.apache.thrift.transport.TTransportException;public class c {public static final String SERVER_IP = "m1";public static final int SERVER_PORT = 10086;public static final int TIMEOUT = 30000;/*** @param args*/public static void main(String[] args) {long startTime=System.currentTimeMillis(); //获取开始时间TTransport transport = null;try {transport = new TFramedTransport(new TSocket(SERVER_IP,SERVER_PORT, TIMEOUT));// 协议要和服务端一致TProtocol protocol = new TBinaryProtocol(transport);idoallThrift.Client client = new idoallThrift.Client(protocol);transport.open();for(int i=1;i<6;i++){Map<String,String> m = new HashMap<String,String>();m.put("a", "idoall");m.put("b", "org"+i);List<String> result = client.CallBack(System.currentTimeMillis(),"java client",m);System.out.println("JAVAClient Call->" + result);}Student s = new Student();s.sid=1111;s.sname="student-idoall-java";s.ssex = true;s.sage = 20000;client.put(s);long endTime = System.currentTimeMillis();System.out.println("本次调用用时:" + endTime + "-" + startTime + "=" + (endTime - startTime)+"毫秒");} catch (TTransportException e) {e.printStackTrace();} catch (TException e) {e.printStackTrace();} finally {if (null != transport) {transport.close();}}}}#配置jar包的MANIFEST文件
1
2
3
4
root@m1:/home/hadoop/thrift_demo/gen-java# vi META-INF/MANIFEST.MFManifest-Version: 1.0Main-Class: idoall.org.demo.cClass-Path: lib/**.jar#制作Maven的描述文件pom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
root@m1:/home/hadoop/thrift_demo/gen-java# vi pom.xml<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>idoall.org.demo</groupId><artifactId>idoall.org.demo</artifactId><version>0.0.1-SNAPSHOT</version><packaging>jar</packaging><name>idoall.org.demo</name><url>http://maven.apache.org</url><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>3.8.1</version><scope>test</scope></dependency><dependency><groupId>org.apache.thrift</groupId><artifactId>libthrift</artifactId><version>0.9.1</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>1.5.8</version></dependency></dependencies><build><plugins><plugin><artifactId>maven-assembly-plugin</artifactId><configuration><archive><manifest><mainClass>idoall.org.demo.c</mainClass></manifest></archive><descriptorRefs><descriptorRef>jar-with-dependencies</descriptorRef></descriptorRefs></configuration></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><source>1.6</source><target>1.6</target></configuration></plugin></plugins></build></project>#使用maven工具,将相关依赖打包到当前目录的target目录中,并生成idoall.org.demo-0.0.1-SNAPSHOT-jar-with-dependencies.jar
1
2
3
4
5
6
7
8
9
10
root@m1:/home/hadoop/thrift_demo/gen-java# mv idoall src/main/java/root@m1:/home/hadoop/thrift_demo/gen-java# mvn assembly:assembly#以下只给出部分提示信息[INFO] ------------------------------------------------------------------------[INFO] BUILD SUCCESS[INFO] ------------------------------------------------------------------------[INFO] Total time: 7.618s[INFO] Finished at: Sun Aug 17 09:36:48 CST 2014[INFO] Final Memory: 12M/29M[INFO] ------------------------------------------------------------------------#运行go服务端
1
2
root@m1:/home/hadoop/thrift_demo# go run s.gothrift server in 0.0.0.0:10086#运行打包后的java客户端
1
2
3
4
5
6
7
root@m1:/home/hadoop/thrift_demo/gen-java# java -jar target/idoall.org.demo-0.0.1-SNAPSHOT-jar-with-dependencies.jar JAVAClient Call->[key:idoall value:org1]JAVAClient Call->[key:idoall value:org2]JAVAClient Call->[key:idoall value:org3]JAVAClient Call->[key:idoall value:org4]JAVAClient Call->[key:idoall value:org5]本次调用用时:1408268973582-ひく1408268973477=わ105毫秒#查看go服务端,可以看到数据的交互
1
2
3
4
5
6
7
8
root@m1:/home/hadoop/thrift_demo# go run s.gothrift server in 0.0.0.0:10086-->from client Call: 1408268973547 java client map[a:idoall b:org1]-->from client Call: 1408268973568 java client map[b:org2 a:idoall]-->from client Call: 1408268973568 java client map[b:org3 a:idoall]-->from client Call: 1408268973568 java client map[b:org4 a:idoall]-->from client Call: 1408268973569 java client map[b:org5 a:idoall]Stduent--->id: 1111 name:student-idoall-java sex:true age:20000 六、扩展阅读
文章中使用的代码提供下载,在这里:http://pan.baidu.com/s/1dDF1rRr
---------------------------------------
博文作者:迦壹
转载声明:可以转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明,谢谢合作!
---------------------------------------