thrift应用举例(c/c++作为服务端、java作为客户端)

来源:互联网 发布:超高速网络 编辑:程序博客网 时间:2024/05/18 03:11

转自:http://dengqsintyt.iteye.com/blog/2005307

最近做的一个项目,后端服务是c++写的,因所有参与这个项目的同事除了me之外,他们都不会c/c++语言。没有办法,我就承担了这个有意思的任务。下面通过实战例子,来剖析thrift的应用。

目录:

1.thrift是干什么用的?

      2.thrift语法?

      3.实战例子

            3.1 环境

            3.2 安装

            3.3 实战例子

      4.小结

 

     1.Thrift是干什么用的?

      Thrift是一个软件框架,用来进行可扩展且跨语言的服务的开发。它结合了功能强大的软件堆栈和代码生成引擎,以构建在 C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, and OCaml 这些编程语言间无缝结合的、高效的服务。Thrift最初由facebook开发,07年四月开放源码,08年5月进入apache孵化器。Thrift允许你定义一个简单的定义文件中的数据类型和服务接口,以作为输入文件,编译器生成代码用来方便地生成RPC客户端和服务器通信的无缝跨编程语言。

    2.Thrift语法

请参考网上其他文章。网上很多,不在赘述。重点了解:基本类型、容器、结构体、枚举、服务即可。

      2.1基本类型:

            bool: 布尔值 (true or false), one byte

            byte: 有符号字节

            i16: 16位有符号整型

            i32: 32位有符号整型

            i64: 64位有符号整型

            double: 64位浮点型

            string: Encoding agnostic text or binary string

            Note that: Thrift不支持无符号整型,因为Thrift目标语言没有无符号整型,无法转换

      2.2容器:

            Thrift容器与流行编程语言的容器类型相对应,采用Java泛型风格。它有3种可用容器类型:

                  list<t1>: 元素类型为t1的有序表,容许元素重复。

                  set<t1>:元素类型为t1的无序表,不容许元素重复。

                  map<t1,t2>: 键类型为t1,值类型为t2的kv对,键不容许重复。

      容器中元素类型可以是除了service外的任何合法Thrift类型(包括结构体和异常)。

      2.3 枚举和结构体

            枚举,和我们平常理解的枚举一样。

            这里只强调结构体就是类似于c/c++中的结构体(几乎一模一样)。类似于java中的实体bean。例子如下:

      枚举:

            enum TweetType {

                 TWEET,       // (1)

               RETWEET = 2, // (2)

                DM = 0xa,    // (3)

              REPLY

            }

 

  结构体:

            struct TxtClass{

                   1: string text,

                   2: string classId,

                   3: double score,

            }

      2.4 服务

      在流行的序列化/反序列化框架(如protocal buffer)中,Thrift是少有的提供多语言间RPC服务的框架。这是Thrift的一大特色。Thrift编译器会根据选择的目标语言为server产生服务接口代码,为client产生stubs。

这里就是thrift自动会生成的方法,我们的服务端也需要器生成的方法中进行编码。例子如下:

            service Twitter {

                      // 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 list are specified using the exact same syntax as

                      // field lists in structs.

                      void ping(),                                    // (1)

                      bool postTweet(1:Tweet tweet);                  // (2)

                      TweetSearchResult searchTweets(1:string query); // (3)

 

                      // The 'oneway' modifier indicates that the client only makes a request and

                      // does not wait for any response at all. Oneway methods MUST be void.

                      oneway void zip()                               // (4)

                }

 

<!--[if !supportLists]-->1.         3.<!--[endif]-->实战例子

      3.1 环境

            centOS6.4 64位操作系统

      3.2 安装

            首先,从官网http://thrift.apache.org/上下载thrift-0.8.0版本,你可以下载最新的版本。

            其次,从网上下载ant 和ivy。放在/usr目录下。

            Ant下载路径:http://ant.apache.org/

            Ivy下载路径:http://ant.apache.org/ivy/

      一切准备就绪,即可安装:

           3.2.1安装ant和ivy(root用户)

第一步:安装 切复制ivy-2.2.0.jar到/usr/local/apache-ant-1.8.2/lib/目录中

       

Shell代码  收藏代码
  1. # tar xzvf apache-ant-1.8.2-bin.tar.gz -C /usr/local   
  2. # tar xzvf apache-ivy-2.2.0-bin-with-deps.tar.gz -C /usr/local  
  3. # cp  /usr/local/apache-ivy-2.2.0/ivy-2.2.0.jar  /usr/local/apache-ant-1.8.2/lib/  
 

 

          第二步:编辑vim  /etc/ profile ,添加如下两行

        

Shell代码  收藏代码
  1. export ANT_HOME=/usr/local/apache-ant-1.8.2   
  2. PATH=$ANT_HOME/bin:$PATH  
 

 

      第三步:解压thrift压缩文件。我用的是thrift-0.8.0.tar.gz

             

Shell代码  收藏代码
  1. tar  zxvf  thrift-0.8.0.tar.gz  
  2. 进入到thrift-0.8.0目录  

 

   第四步:包的检查、安装(如果缺少包,请安装缺少的包)

       

Shell代码  收藏代码
  1. ./configure --prefix=/usr/local/ --with-boost=/usr/local --without-php  
  2. make  
  3. make install  

 

   第五步:

   在终端输入:thrift –version  查看是否安装成功。

 

3.3 实战例子

特别注意:如下例子:演示的是thrift-0.7.0版本(因我服务器上安装的此版本)

    1.定义thrift文件:user.thrift     

Thrift代码  收藏代码
  1. struct User{  
  2.  1: string uid,  
  3.  2: string uname,  
  4.  3: bool usex,  
  5.  4: i16 uage,  
  6. }  
  7. service UserService{  
  8.  void add(1: User u),  
  9.  User get(1: string uid),  
  10. }  
 

 

2.通过thrift的shell工具命令生成c++,java代码框架 

 

Shell代码  收藏代码
  1. thrift -r --gen cpp user.thrift     
  2. thrift -r --gen java user.thrift  
   通过执行以上命令:会生成子目录gen-cpp,gen-java。
     3.通过执行如下命令,生成C/C++服务端代码
Shell代码  收藏代码
  1. cp gen-cpp/UserService_server.skeleton.cpp UserServer.cpp  
 
     4.修改服务端的代码,如下所示
     
Cpp代码  收藏代码
  1. // This autogenerated skeleton file illustrates how to build a server.  
  2. // You should copy it to another filename to avoid overwriting it.  
  3.   
  4. #include <string>  
  5. #include <iostream>   
  6. #include "UserService.h"    
  7. #include <config.h>     
  8. #include <protocol/TCompactProtocol.h>    
  9. #include <server/TSimpleServer.h>    
  10. #include <transport/TServerSocket.h>    
  11. #include <transport/TBufferTransports.h>    
  12. #include <concurrency/ThreadManager.h>    
  13. #include <concurrency/PosixThreadFactory.h>    
  14. #include <server/TThreadPoolServer.h>    
  15. #include <server/TThreadedServer.h>    
  16.     
  17. using namespace ::apache::thrift;    
  18. using namespace ::apache::thrift::protocol;    
  19. using namespace ::apache::thrift::transport;    
  20. using namespace ::apache::thrift::server;    
  21. using namespace ::apache::thrift::concurrency;    
  22.     
  23. using boost::shared_ptr;  
  24. using namespace std;   
  25.   
  26. class UserServiceHandler : virtual public UserServiceIf {  
  27.  public:  
  28.   UserServiceHandler() {  
  29.     // Your initialization goes here  
  30.   }  
  31.   
  32.   void add(const User& u) {  
  33.     // Your implementation goes here  
  34.     cout << "调用add方法" << endl;  
  35.   }  
  36.   
  37.   void get(User& _return, const std::string& uid) {  
  38.     // Your implementation goes here  
  39.     _return.uid = "001";  
  40.     _return.uname = "dengqs";  
  41.     _return.usex = 1;  
  42.     _return.uage = 3;  
  43.     cout << "uid = " << _return.uid << endl;  
  44.     cout << "调用get方法" << endl;  
  45.   }  
  46.   
  47. };  
  48.   
  49. int main(int argc, char **argv) {  
  50.   int port = 9090;  
  51.   shared_ptr<UserServiceHandler> handler(new   UserServiceHandler());    
  52.   shared_ptr<TProcessor> processor(new UserServiceProcessor(handler));    
  53.   shared_ptr<TProtocolFactory> protocolFactory(new TCompactProtocolFactory());    
  54.   shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());    
  55.   shared_ptr<TServerTransport> serverTransport(new TServerSocket(9090));    
  56.   
  57.   shared_ptr<ThreadManager> threadManager = ThreadManager::newSimpleThreadManager(10);    
  58.   shared_ptr<PosixThreadFactory> threadFactory = shared_ptr<PosixThreadFactory>(new PosixThreadFactory());    
  59.   threadManager->threadFactory(threadFactory);    
  60.   threadManager->start();    
  61.   printf("start user server...\n");    
  62.   
  63.   TThreadPoolServer server(processor, serverTransport,    transportFactory, protocolFactory, threadManager);    
  64.   server.serve();    
  65.   return 0;  
  66. }  
 注意:我这里使用的是TCompactProtocol,则需要#include <config.h> ,还有就是Blocking的多线程服务器。
 
     5.书写Makefile文件,如下所示: 
Shell代码  收藏代码
  1. BOOST_DIR = /usr/include/boost/  
  2. THRIFT_DIR = /usr/local/include/thrift  
  3. LIB_DIR = /usr/local/lib  
  4. GEN_SRC = ./gen-cpp/user_types.cpp ./gen-cpp/user_constants.cpp ./gen-cpp/UserService.cpp  
  5. default: server  
  6. server: UserServer.cpp  
  7.         g++ -g -o UserServer -I${THRIFT_DIR} -I${BOOST_DIR}  -I./gen-cpp -L${LIB_DIR} -lthrift UserServer.cpp ${GEN_SRC}  
 注意:在当前目录下,执行:make命令。看是否有可执行文件UserServer生成。如果有,则编译成功。
 
     6.书写简单的运行脚本:run.sh文件,如下所示: 
Shell代码  收藏代码
  1. nohup ./UserServer  >log  2>&1 &  
   
       7.以上步骤,c++服务端操作完毕,执行如下命令开启服务:
Shell代码  收藏代码
  1. ./run.sh  
  2. 或者  
  3. ./UserServie  
 
      8.写java client文件Demo.java
         注意需要引入thrift相关的jar。并且需要把第2步生成的gen-java目录下的文件拷贝到你的测试程序中。
         
Java代码  收藏代码
  1. import org.apache.thrift.TException;  
  2. import org.apache.thrift.protocol.TCompactProtocol;  
  3. import org.apache.thrift.protocol.TProtocol;  
  4. import org.apache.thrift.transport.TSocket;  
  5. import org.apache.thrift.transport.TTransport;  
  6. import org.apache.thrift.transport.TTransportException;  
  7.   
  8. import com.intyt.thrift.client.User;  
  9. import com.intyt.thrift.client.UserService;  
  10.   
  11. public class Demo {  
  12.       
  13.     public void start(){  
  14.         try {  
  15.               
  16.             String ip = "10.x.x.x"//服务端的ip  
  17.             int port = 9090;//端口  
  18.               
  19.             TTransport socket = new TSocket(ip,port);  
  20.             TProtocol protocol = new TCompactProtocol(socket);  
  21.             UserService.Client client = new UserService.Client(protocol);  
  22.             socket.open();  
  23.               
  24.             User u = new User();    
  25.             u.uid="003";    
  26.             u.uname="dengqs_test";    
  27.             u.usex=true;    
  28.             u.uage=3;  
  29.             client.add(u);  
  30.               
  31.             System.out.println(client.get(u.uid));    
  32.             socket.close();   
  33.         }catch (TTransportException e) {  
  34.             e.printStackTrace();  
  35.         } catch (TException e) {    
  36.             e.printStackTrace();    
  37.         }  
  38.     }  
  39.     public static void main(String[] args) {  
  40.         Demo demo = new Demo();  
  41.         demo.start();  
  42.     }  
  43.   
  44. }  
 
以上步骤,可查看服务端和客户端时候有相关打印输出。如果有预期的打印输出,则测试成功。
祝你好运。
原创粉丝点击