Thrift相关知识总结
2014-10-14 18:41
225 查看
1 Thrift简介
目前流行的服务调用方式有很多种,例如基于 SOAP 消息格式的 Web Service,基于 JSON 消息格式的 RESTful 服务等。其中所用到的数据传输方式包括 XML,JSON 等,然而 XML 相对体积太大,传输效率低,JSON 体积较小,新颖,但还不够完善。本文将介绍由Facebook 开发的远程服务调用框架 Apache Thrift,它采用接口描述语言定义并创建服务,支持可扩展的跨语言服务开发,所包含的代码生成引擎可以在多种语言中,如 C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa,Smalltalk 等创建高效的、无缝的服务,其传输数据采用二进制格式,相对 XML 和 JSON 体积更小,对于高并发、大数据量和多语言的环境更有优势。
2 Thrift架构
Thrift 包含一个完整的堆栈结构用于构建客户端和服务器端。下图描绘了 Thrift 的整体架构。图 1. 架构图
如图所示,图中黄色部分是用户实现的业务逻辑,褐色部分是根据 Thrift 定义的服务接口描述文件生成的客户端和服务器端代码框架,红色部分是根据Thrift 文件生成代码实现数据的读写操作。红色部分以下是 Thrift 的传输体系、协议以及底层 I/O 通信,使用 Thrift 可以很方便的定义一个服务并且选择不同的传输协议和传输层而不用重新生成代码。
Thrift 服务器包含用于绑定协议和传输层的基础架构,它提供阻塞、非阻塞、单线程和多线程的模式运行在服务器上,可以配合服务器 / 容器一起运行,可以和现有的 J2EE 服务器 /Web 容器无缝的结合。
3 Thrift安装
在一个干净的系统上,很快就能完成。Thrift至少会依赖于两个系统中一般不会带的库:libevent,boost。 http://thrift.apache.org/download/
libevent到这里下载:http://monkey.org/~provos/libevent/
boost 到这里下载:http://www.boost.org/
安装libevent:
./configure
make
makeinstall
安装boost(boost不像一般的Linux源码安装包一样,它的安装不是configure,make,makeinstall,有点怪):
./bootstrap.sh
./b2
./b2install
安装Thrift:
./configure
make
makeinstall
4 Thrift文件的编写
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数据。
8) binary型,为java提供
b. 结构体:
有点类似c的结构体。
型如:
struct Work {
1: i32 num1 =0,
2: i32 num2,
3: Operation op,
4: optionalstring comment,
}
c. 容器
1) list类型。
指一组有序元素的集合,类似于java的ArrayList类。
typedefi32 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'}
2. 服务
有了数据结构,那么就该对数据进行操作。thrift这里所说的服务,不可能针对我们自己的业务逻辑,而是指的是服务端从端口读取数据,客户端传入数据的一套方法。
service <服务名>{ <返回类型> <方法名>(参数) throws <异常> } |
const i32 a = 1 const i32 b = 2 const stringc ="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:stringwhere; } service Hello{ fget_f(1:f gg) throws (1:Exception e) } |
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{ fget_f(1:f gg) throws (Exception, e) } |
修改
1.常量量如a,b,c,d, e要使用const修饰。
2. 如果都使用了const修饰,但有;号,还是不成功,尽管有的人说thrift对;不敏感,那还是估计看版本的,这里我使用的是最新的0.8版本。也就是说,如果你是一个java或者php程序员,请注意没有";"
3. 静态变量请赋值,如consti32 a = "helloworld"
4. 结构体内部的属性请指定参数类型,因为结构体内部属性和外部的静态属性没有任何关系。
5. 异常之间没有“,”分割,以空格代替
6. Exception类型请定义。
7. throws参数也要指定是第几个参数
好了,修改后的thrift脚本变为
5 编译thriift文件生成代码
Windows:thrift-0.7.0.exe -r -gen java**.thrift //生成java 代码
thrift-0.7.0.exe -r -gen php**.thrift //生成php代码
thrift-0.7.0.exe -r -gen py**.thrift //生成python代码
thrift-0.7.0.exe -r -gen as3 **.thrift //生成as3代码
thrift-0.7.0.exe -r -gen cpp**.thrift //生成C++代码
Linux:
thrift -r -genjava **.thrift //生成java 代码
thrift -r -genphp **.thrift //生成php代码
thrift -r -genpy **.thrift //生成python代码
thrift -r -genas3 **.thrift //生成as3代码
thrift -r -gencpp **.thrift //生成C++代码
6 Thrift服务器与客户端通信样例
6.1 客户端JAVA,服务端JAVA
创建一个简单的服务Hello。首先根据 Thrift 的语法规范编写脚本文件 Hello.thrift,代码如下:
清单1:Hello.thrift
namespace java service.demo service Hello{ string helloString(1:string para) i32 helloInt(1:i32 para) bool helloBoolean(1:bool para) void helloVoid() string helloNull() } |
IDL 语法编写。使用 Thrift 工具编译 Hello.thrift,就会生成相应的 Hello.java 文件。该文件包含了在 Hello.thrift 文件中描述的服务 Hello 的接口定义,即 Hello.Iface 接口,以及服务调用的底层通信细节,包括客户端的调用逻辑 Hello.Client 以及服务器端的处理逻辑 Hello.Processor,用于构建客户端和服务器端的功能。
创建HelloServiceImpl.java 文件并实现 Hello.java 文件中的 Hello.Iface 接口,代码如下:
清单2:HelloServiceImpl.java
package service.demo; import org.apache.thrift.TException; public class HelloServiceImpl implementsHello.Iface { @Override public boolean helloBoolean(boolean para)throws TException { return para; } @Override public int helloInt(int para) throwsTException { try { Thread.sleep(20000); } catch (InterruptedException e) { e.printStackTrace(); } return para; } @Override public String helloNull() throws TException{ return null; } @Override public String helloString(String para)throws TException { return para; } @Override public void helloVoid() throws TException { System.out.println("HelloWorld"); } } |
清单3:HelloServiceServer.java
package service.server; import org.apache.thrift.TProcessor; importorg.apache.thrift.protocol.TBinaryProtocol; importorg.apache.thrift.protocol.TBinaryProtocol.Factory; import org.apache.thrift.server.TServer; importorg.apache.thrift.server.TThreadPoolServer; importorg.apache.thrift.transport.TServerSocket; importorg.apache.thrift.transport.TTransportException; import service.demo.Hello; import service.demo.HelloServiceImpl; public class HelloServiceServer { /** * 启动 Thrift 服务器 * @param args */ public static void main(String[] args) { try { // 设置服务端口为 7911 TServerSocket serverTransport = newTServerSocket(7911); // 设置协议工厂为TBinaryProtocol.Factory Factory proFactory = newTBinaryProtocol.Factory(); // 关联处理器与 Hello 服务的实现 TProcessor processor = newHello.Processor(new HelloServiceImpl()); TServer server = newTThreadPoolServer(processor, serverTransport, proFactory); System.out.println("Startserver on port 7911..."); server.serve(); } catch (TTransportException e) { e.printStackTrace(); } } } |
清单4:[b] HelloServiceClient.java[/b]
package service.client; import org.apache.thrift.TException; importorg.apache.thrift.protocol.TBinaryProtocol; import org.apache.thrift.protocol.TProtocol; import org.apache.thrift.transport.TSocket; import org.apache.thrift.transport.TTransport; importorg.apache.thrift.transport.TTransportException; import service.demo.Hello; public class HelloServiceClient { /** * 调用 Hello 服务 * @param args */ public static void main(String[] args) { try { // 设置调用的服务地址为本地,端口为7911 TTransport transport = newTSocket("localhost", 7911); transport.open(); // 设置传输协议为TBinaryProtocol TProtocol protocol = newTBinaryProtocol(transport); Hello.Client client = newHello.Client(protocol); // 调用服务的 helloVoid 方法 client.helloVoid(); transport.close(); } catch (TTransportException e) { e.printStackTrace(); } catch (TException e) { e.printStackTrace(); } } } |
)。
6.2 客户端C++,服务端JAVA
清单1:[b]Hello.thrift[/b]namespace java service.demo service Hello{ string helloString(1:string para) i32 helloInt(1:i32 para) bool helloBoolean(1:bool para) void helloVoid() string helloNull() } |
DefinitionLanguage) 描述性语言的一种具体实现。因此,以上的服务描述文件使用 IDL 语法编写。使用 Thrift 工具以-cpp参数编译Hello.thrift,就会生成相应的 *.c和*.h 文件。使用 Thrift 工具以-java参数编译Hello.thrift,就会生成相应的.java文件。其中服务器端java代码同上,在此不再列出。
清单2:[b]Hello_client.cpp[/b]
#include "Hello.h" // Asan example #include <transport/TSocket.h> #include <transport/TBufferTransports.h> #include <protocol/TBinaryProtocol.h> using namespace apache::thrift; using namespace apache::thrift::protocol; using namespace apache::thrift::transport; int main(int argc, char **argv) { boost::shared_ptr<TSocket>socket(new TSocket("localhost", 7911));//注意端口号的匹配 boost::shared_ptr<TTransport> transport(newTBufferedTransport(socket)); boost::shared_ptr<TProtocol>protocol(new TBinaryProtocol(transport)); HelloClient client(protocol); transport->open(); client.helloVoid(); transport->close(); return 0; } |
BOOST_DIR= /usr/local/include/boost/ THRIFT_DIR= /usr/local/include/thrift/ LIB_DIR= /usr/local/lib/ GEN_SRC:= Hello.cpp Hello_constants.cpp Hello_types.cpp default:hello_client hello_client:Hello_client.cpp g++ -DHAVE_NETINET_IN_H -o hello_client-I${THRIFT_DIR} -I${BOOST_DIR} -I./ -L${LIB_DIR} -lthrift Hello_client.cpp${GEN_SRC} clean: $(RM) -r hello_client |
文件放到同一目录下,删除Hello_server.skeleton.cpp文件,然后执行make命令进行编译。
执行./hello_client
相关文章推荐
- DataGrid相关知识总结(转的)
- DataGrid相关知识总结(收集自各位老大处)
- JAVA相关基础知识总结(连载)-3
- JAVA相关基础知识总结(连载)-8
- JAVA相关基础知识总结(连载)-7
- DataGrid相关知识总结(收集自各位老大处)
- JAVA相关基础知识总结(连载)-12
- JAVA相关基础知识总结(连载)
- [转]WinForm开发,窗体显示和窗体传值相关知识总结
- JAVA相关基础知识总结(连载)-10
- Unicode相关知识总结
- SOA相关知识总结
- 多进程编程的相关知识总结(三)
- JAVA相关基础知识总结(连载)-2
- DataGrid相关知识总结
- DataGrid相关知识总结(转的)
- 多进程编程的相关知识总结(二)
- DataGrid相关知识总结(收集)
- JAVA相关基础知识总结(连载)-5
- JAVA相关基础知识总结(连载)-11