您的位置:首页 > 运维架构 > Apache

Apache Thrift的简单使用

2013-07-17 19:07 621 查看

Apache Thrift的简单使用

 

测试thrift python的时候,先是报错no module named thrift.Thrift,

通过进入tar包中的lib/py执行 sudo python setup.py install。

 

----------------------

 http://blog.csdn.net/amuseme_lu/article/details/6262572

1. 简单介绍

Thrift是Facebook的一个开源项目,主要是一个跨语言的服务开发框架。它有一个代码生成器来对它所定义的IDL定义文件自动生成服务代码框架。用户只要在其之前进行二次开发就行,对于底层的RPC通讯等都是透明的。目前它支持的语言有C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, Smalltalk, and OCaml.

 

2. 下载与安装

可以在http://incubator.apache.org/thrift/download/去下载它的最新版本,目前最新版本是0.5.0。另外你也可以check出它的svn,方法如下:

svn co http://svn.apache.org/repos/asf/thrift/trunk thrift

cd thrift

 

在它的jira中看到,它的0.6版本也很快就会出来了。

 

我的本本是debian 6.0,如果用ubuntu的兄弟安装方法也是一样的

[c-sharp]
view plaincopyprint?

tar -zxvf thrift-0.5.0.tar.gz  
cd thrift-0.5.0  
./configure  
make   
sudo make install  

[c-sharp]
view plaincopyprint?

thrift -version  

thrift -version
 

 

3. 一个简单的例子

在thrift源代码目录有一个叫tutorial的目录,进行其中后运行thrift命令生成相应的服务代码:

[c-sharp]
view plaincopyprint?

$ thrift -r --gen cpp tutorial.thrift // -r对其中include的文件也生成服务代码 -gen是生成服务代码的语言  

[c-sharp]
view plaincopyprint?

lemo@debian:~/Workspace/Facebook/Thrift/thrift-0.5.0/tutorial/cpp$ ./CppServer  
Starting the server...  
ping()  
add(1,1)  
calculate(1,{4,1,0})  
calculate(1,{2,15,10})  
getStruct(1)  

lemo@debian:~/Workspace/Facebook/Thrift/thrift-0.5.0/tutorial/cpp$ ./CppServer
Starting the server...
ping()
add(1,1)
calculate(1,{4,1,0})
calculate(1,{2,15,10})
getStruct(1)
 

 

如果你的终端中也出现了如上的信息,恭喜你,运行成功了。如果在运行CppServer的时候找不到动态库,看看你是不是运行了make install,如果运行了,再运行一下sudo ldconfig试试。再用ldd CppServer看一下它有没有找到相应的动态库了。

 

4. 例子分析

 

4.1 Thrift IDL的分析

 

这边有两个IDL文件,内容如下:

 

[c-sharp]
view plaincopyprint?

shared.thrift  
---------------  
**  
 * This Thrift file can be included by other Thrift files that want to share  
 * these definitions.  
 */  
namespace cpp shared  
namespace java shared  
namespace perl shared  
// 这里定义了一个结构体,没有定义方法,对应于生成的代码在gen-cpp中的shared_types.h中,其中有一个class叫SharedStruct,  
// 有没有看到其中有两个方法叫read和write,这就是用来对其进行序列化与把序列化的方法.  
// 对了,其中的i32是Thrift IDL中定义的变量类型,对应于c++语言中的int32_t
  
struct SharedStruct {      
  1: i32 key  
  2: string value  
}  
// 这里定义的一个服务,它语义上类似于面向对象中的定义一个接口,thrift的编译器会对其产生一套实现其接口的客户端与服务端方法  
// 服务的一般定义格式如下   
// service <name>   
// <returntype> <name>(<arguments>)   
// [ throws (<exceptions>)]   
//   ...   
// }   
service SharedService {  
  SharedStruct getStruct(1: i32 key)  
}  
tutorial.thrift  
----------------  
/** 
 * Thrift files can reference other Thrift files to include common struct 
 * and service definitions. These are found using the current path, or by 
 * searching relative to any paths specified with the -I compiler flag. 
 * 
 * Included objects are accessed using the name of the .thrift file as a 
 * prefix. i.e. shared.SharedObject 
 */  
 // 这个IDL包含了另一个IDL,也就是说另一个IDL中的对象与服务对其时可见的
  
include "shared.thrift"  
/** 
 * Thrift files can namespace, package, or prefix their output in various 
 * target languages. 
 */  
 // 这里定义了一些语言的namespace空间   
namespace cpp tutorial  
namespace java tutorial  
namespace php tutorial  
namespace perl tutorial  
/** 
 * Thrift lets you do typedefs to get pretty names for your types. Standard 
 * C style here. 
 */  
 // 自定义类型   
typedef i32 MyInteger  
/** 
 * Thrift also lets you define constants for use across languages. Complex 
 * types and structs are specified using JSON notation. 
 */  
 // 定义一些变量   
const i32 INT32CONSTANT = 9853  
const map<string,string> MAPCONSTANT = {'hello':'world', 'goodnight':'moon'}  
/** 
 * You can define enums, which are just 32 bit integers. Values are optional 
 * and start at 1 if not supplied, C style again. 
 */  
 // 定义枚举类型   
enum Operation {  
  ADD = 1,  
  SUBTRACT = 2,  
  MULTIPLY = 3,  
  DIVIDE = 4  
}  
/** 
 * Structs are the basic complex data structures. They are comprised of fields 
 * which each have an integer identifier, a type, a symbolic name, and an 
 * optional default value. 
 * 
 * Fields can be declared "optional", which ensures they will not be included 
 * in the serialized output if they aren't set.  Note that this requires some 
 * manual management in some languages. 
 */  
struct Work {  
  1: i32 num1 = 0,  
  2: i32 num2,  
  3: Operation op,          
  4: optional string comment, //这里的optional字段类型表示如果这个字段的值没有被赋值,它就不会被序列化输出  
}  
/** 
 * Structs can also be exceptions, if they are nasty. 
 */  
 // 这里定义了一些异常   
exception InvalidOperation {  
  1: i32 what,  
  2: string why  
}  
/** 
 * Ahh, now onto the cool part, defining a service. Services just need a name 
 * and can optionally inherit from another service using the extends keyword. 
 */  
 // 这里是定义服务,它继承了shared的服务   
service Calculator extends shared.SharedService {  
  /** 
   * A method definition looks like C code. It has a return type, arguments, 
   * and optionally a list of exceptions that it may throw. Note that argument 
   * lists and exception lists are specified using the exact same syntax as 
   * field lists in struct or exception definitions. 
   */  
   void ping(),  
   i32 add(1:i32 num1, 2:i32 num2),  
   i32 calculate(1:i32 logid, 2:Work w) throws (1:InvalidOperation ouch),  
   /** 
    * This method has a oneway modifier. That means the client only makes 
    * a request and does not listen for any response at all. Oneway methods 
    * must be void. 
    */  
   oneway void zip()  
}  

[c-sharp]
view plaincopyprint?

  int main(int argc, char **argv) {  
// 定义了RPC的协议工厂,这里使用了二进制协议,你不可以使用别的协议,如JSON,Compact等
  
shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());  
// 这里生成用户实现的CalculatorHandler服务,再把其帮定到一个Processor上去,它主要用于处理协议的输入与输出流  
shared_ptr<CalculatorHandler> handler(new CalculatorHandler());  
shared_ptr<TProcessor> processor(new CalculatorProcessor(handler));  
// 生成一个传输通道,这里使用了Socket方式   
shared_ptr<TServerTransport> serverTransport(new TServerSocket(9090));  
// 生成一个传输工厂,主要用于把上面的transport转换成一个新的应用层传输通道  
shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());  
// 生成一个简单的服务端,这是一个单线程的服务端    
TSimpleServer server(processor,  
                      serverTransport,  
                      transportFactory,  
                      protocolFactory);  
// 你也可以生成一个多线程的服务端,就是对其加入线程池。但它现在还不支持进程池,但可能会在0.7版本中进行支持。  
 /** 
  * Or you could do one of these 
 shared_ptr<ThreadManager> threadManager = 
   ThreadManager::newSimpleThreadManager(workerCount); 
 shared_ptr<PosixThreadFactory> threadFactory = 
   shared_ptr<PosixThreadFactory>(new PosixThreadFactory()); 
 threadManager->threadFactory(threadFactory); 
 threadManager->start(); 
 TThreadPoolServer server(processor, 
                          serverTransport, 
                          transportFactory, 
                          protocolFactory, 
                          threadManager); 
 TThreadedServer server(processor, 
                        serverTransport, 
                        transportFactory, 
                        protocolFactory); 
 */  
 printf("Starting the server.../n");  
 server.serve();   // 启动服务   
 printf("done./n");  
 return 0;  
}  

int main(int argc, char **argv) {
// 定义了RPC的协议工厂,这里使用了二进制协议,你不可以使用别的协议,如JSON,Compact等
shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
// 这里生成用户实现的CalculatorHandler服务,再把其帮定到一个Processor上去,它主要用于处理协议的输入与输出流
shared_ptr<CalculatorHandler> handler(new CalculatorHandler());
shared_ptr<TProcessor> processor(new CalculatorProcessor(handler));
// 生成一个传输通道,这里使用了Socket方式
shared_ptr<TServerTransport> serverTransport(new TServerSocket(9090));
// 生成一个传输工厂,主要用于把上面的transport转换成一个新的应用层传输通道
shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());
// 生成一个简单的服务端,这是一个单线程的服务端
TSimpleServer server(processor,
serverTransport,
transportFactory,
protocolFactory);
// 你也可以生成一个多线程的服务端,就是对其加入线程池。但它现在还不支持进程池,但可能会在0.7版本中进行支持。
/**
* Or you could do one of these
shared_ptr<ThreadManager> threadManager =
ThreadManager::newSimpleThreadManager(workerCount);
shared_ptr<PosixThreadFactory> threadFactory =
shared_ptr<PosixThreadFactory>(new PosixThreadFactory());
threadManager->threadFactory(threadFactory);
threadManager->start();
TThreadPoolServer server(processor,
serverTransport,
transportFactory,
protocolFactory,
threadManager);
TThreadedServer server(processor,
serverTransport,
transportFactory,
protocolFactory);
*/
printf("Starting the server.../n");
server.serve();   // 启动服务
printf("done./n");
return 0;
}
 

 

 

另一部分如下:

[c-sharp]
view plaincopyprint?

// 这一部分主要是实现接口类,用于提供给相应的服务使用。   
class CalculatorHandler : public CalculatorIf {  
public:  
 CalculatorHandler() {}  
 void ping() {  
   printf("ping()/n");  
 }  
 int32_t add(const int32_t n1, const int32_t n2) {  
   ...  
 }  
 int32_t calculate(const int32_t logid, const Work &work) {  
 ...  
 }  
 void getStruct(SharedStruct &ret, const int32_t logid) {  
 ...  
 }  
 void zip() {  
   printf("zip()/n");  
 }  
protected:  
 map<int32_t, SharedStruct> log;  
};  

[c-sharp]
view plaincopyprint?

int main(int argc, char** argv) {  
 // 生成一个Socket连接到服务端   
 shared_ptr<TTransport> socket(new TSocket("localhost", 9090));  
 // 对Socket通道加入缓冲功能   
 shared_ptr<TTransport> transport(new TBufferedTransport(socket));  
 // 生成相应的二进制协议,这个要和服务端一致,不然会出现协议版本不对的错误   
 shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));  
 // 生成客户端的服务对象   
 CalculatorClient client(protocol);  
 try {  
   transport->open(); // 加开服务   
   // 调用事先定义好的服务接口   
   client.ping();  
   printf("ping()/n");  
   int32_t sum = client.add(1,1);  
   printf("1+1=%d/n", sum);  
   Work work;  
   work.op = Operation::DIVIDE;  
   work.num1 = 1;  
   work.num2 = 0;  
   try {  
     int32_t quotient = client.calculate(1, work);  
     printf("Whoa? We can divide by zero!/n");  
   } catch (InvalidOperation &io) {  
     printf("InvalidOperation: %s/n", io.why.c_str());  
   }  
   work.op = Operation::SUBTRACT;  
   work.num1 = 15;  
   work.num2 = 10;  
   int32_t diff = client.calculate(1, work);  
   printf("15-10=%d/n", diff);  
   // Note that C++ uses return by reference for complex types to avoid  
   // costly copy construction   
   SharedStruct ss;  
   client.getStruct(ss, 1);  
   printf("Check log: %s/n", ss.value.c_str());  
   // 关闭服务   
   transport->close();  
 } catch (TException &tx) {  
   printf("ERROR: %s/n", tx.what());  
 }  
}  

int main(int argc, char** argv) {
// 生成一个Socket连接到服务端
shared_ptr<TTransport> socket(new TSocket("localhost", 9090));
// 对Socket通道加入缓冲功能
shared_ptr<TTransport> transport(new TBufferedTransport(socket));
// 生成相应的二进制协议,这个要和服务端一致,不然会出现协议版本不对的错误
shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));
// 生成客户端的服务对象
CalculatorClient client(protocol);
try {
transport->open(); // 加开服务
// 调用事先定义好的服务接口
client.ping();
printf("ping()/n");
int32_t sum = client.add(1,1);
printf("1+1=%d/n", sum);
Work work;
work.op = Operation::DIVIDE;
work.num1 = 1;
work.num2 = 0;
try {
int32_t quotient = client.calculate(1, work);
printf("Whoa? We can divide by zero!/n");
} catch (InvalidOperation &io) {
printf("InvalidOperation: %s/n", io.why.c_str());
}
work.op = Operation::SUBTRACT;
work.num1 = 15;
work.num2 = 10;
int32_t diff = client.calculate(1, work);
printf("15-10=%d/n", diff);
// Note that C++ uses return by reference for complex types to avoid
// costly copy construction
SharedStruct ss;
client.getStruct(ss, 1);
printf("Check log: %s/n", ss.value.c_str());
// 关闭服务
transport->close();
} catch (TException &tx) {
printf("ERROR: %s/n", tx.what());
}
}
 

4.2.3 其它代码的实现

在tutorial目录中有其它代码的例子,如erl,java,python,perl,ruby等。

 

5 参考

1. http://incubator.apache.org/thrift/
2. http://incubator.apache.org/thrift/static/thrift-20070401.pdf
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: