HMLLF / Blog

个人分享博客
0 stars 0 forks source link

thrift安装教程 #9

Open HMLLF opened 5 years ago

HMLLF commented 5 years ago

thrift是什么

thrift主要用于各个服务之间的RPC通信,支持跨语言。thrift是一个典型的CS结构,客户端和服务端可以使用不同的语言开发,thrift通过IDL(Interface Description Language)来关联客户端和服务端。thrift的整体架构图如下图所示 在这里插入图片描述 图中Your Code是用户实现的业务逻辑,接下来的FooService.Client和Foo.write()/read()是thrift根据IDL生成的客户端和服务端的代码,对应于RPC中Client stub和Server stub。TProtocol 用来对数据进行序列化与反序列化,具体方法包括二进制,JSON 或者 Apache Thrift 定义的格式。TTransport 提供数据传输功能,使用 Apache Thrift 可以方便地定义一个服务并选择不同的传输协议。 如下图所示为thrift的网络栈结构 在这里插入图片描述 thirft使用socket进行数据传输,数据以特定的格式发送,接收方进行解析。我们定义好thrift的IDL文件后,就可以使用thrift的编译器来生成双方语言的接口、model,在生成的model以及接口代码中会有解码编码的代码。

TTransport层

代表thrift的数据传输方式,thrift定义了如下几种常用数据传输方式

此外thrift还支持以下容器类型:

thrift容器中元素的类型可以是除了service之外的任何类型,包括exception

thirft支持struct类型,目的就是讲一些数据聚合在一起,方便传输管理,struct定义形式如下:

struct People {
    1:string name;
    2:i32 age;
    3:string gender;
}

thrift支持枚举类型,定义形式如下:

enum Gender {
    MALE,
    FEMALE
}

thrift支持自定义异常类型exception,异常定义形式如下:

exception RequestException {
    1:i32 code;
    2:string reason;
}

thrift定义服务相当于Java中创建接口一样,创建的service经过代码生thrift代码生成工具编译后就会生成客户端和服务端的框架代码,service的定义形式如下:

service HelloWorldService {
    // service中可以定义若干个服务,相当于Java Interface中定义的方法
    string doAction(1:string name, 2:i32 age);
}

thrift支持给类型定义别名,如下所示:

typedef i32 int
typedef i64 long

thrift也支持常量的定义,使用const关键字:

const i32 MAX_RETRIES_TIME = 10;
const string MY_WEBSITE = "http://facebook.com";

thrift支持命名空间,命名空间相当于Java中的package,主要用于组织代码,thrift使用关键字namespace定义命名空间,格式是namespace 语言名 路径,如下示例所示:

namespace java com.test.thrift.demo

thrift也支持文件包含,相当于CPP中的include,Java中的import,使用关键字include:

include "global.thrift"

#///**/都可以作为thrift文件中的注释。

thrift提供两个关键字requiredoptional,分别用于表示对应的字段是必填的还是可选的(推荐尽量使用optional),如下所示:

struct People {
    1:required string name;
    2:optional i32 age;
}

原文参考:[thrift] thrift基本原理及使用

thrift优点

Thrift一些已经明确的优点包括:

安装环境

安装过程

  1. 更新系统
sudo yum -y update
  1. 安装wget
sudo yum install -y wget
  1. 更新autoconf
autoconf --version    //查看设备autoconf版本,版本高则可忽略更新
wget http://ftp.gnu.org/gnu/autoconf/autoconf-2.69.tar.gz
tar xvf autoconf-2.69.tar.gz
cd autoconf-2.69
./configure --prefix=/usr
make
sudo make install
cd ..
  1. 更新automake
automake --version    //查看设备automake版本,版本高则可忽略更新
wget http://ftp.gnu.org/gnu/automake/automake-1.14.tar.gz
tar xvf automake-1.14.tar.gz
cd automake-1.14
./configure --prefix=/usr
make
sudo make install
cd ..
  1. 更新bison
bison --version      //查看设备bison版本,版本高则可忽略更新
wget http://ftp.gnu.org/gnu/bison/bison-2.5.1.tar.gz
tar xvf bison-2.5.1.tar.gz
cd bison-2.5.1
./configure --prefix=/usr
make
sudo make install
cd ..
  1. 安装C++库依赖
sudo yum -y install libevent-devel zlib-devel openssl-devel
  1. 更新boost
wget http://sourceforge.net/projects/boost/files/boost/1.53.0/boost_1_53_0.tar.gz
tar xvf boost_1_53_0.tar.gz
cd boost_1_53_0
./bootstrap.sh
sudo ./b2 install

boost比较大,建议直接到89上/home/threepart/上拿1.59版压缩文件。

  1. 安装thrift
git clone https://github.com/apache/thrift.git
cd thrift
./bootstrap.sh
./configure --with-lua=no
make
sudo make install

也可以安装别的版本,两台设备上都是装的0.12.0版本
参考文章:Apache thrift官方安装文档




两台设备之间进行通信并抓包

1.定义idl文件acsuser.thrift,用来生成初始的服务器端框架
struct User{  
 1: string uid,  
 2: string uname,  
 3: bool usex,  
 4: i16 uage,  
}  
service UserService{  
 void add(1: User u),  
 User get(1: string uid),  
}  
2.生成c++代码框架
thrift -r --gen cpp acsuser.thrift 

执行完这个命令可以看到生成了gen-cpp文件夹,这就是我们的框架。里面的文件有:

acsuser_constants.cpp               
acsuser_constants.h      
UserService.cpp
acsuser_types.cpp         
UserService.h
acsuser_types.h        
UserService_server.skeleton.cpp   //服务端代码,程序修改主要在这里完成
3.修改UserService_server.skeleton.cpp
#include "UserService.h"  
#include <config.h>  
//#include <protocol/TBinaryProtocol.h>  
#include <protocol/TCompactProtocol.h>  
#include <server/TSimpleServer.h>  
#include <transport/TServerSocket.h>  
#include <transport/TBufferTransports.h>  
#include <concurrency/ThreadManager.h>  
#include <concurrency/PosixThreadFactory.h>  
#include <server/TThreadPoolServer.h>  
#include <server/TThreadedServer.h>  

using namespace ::apache::thrift;  
using namespace ::apache::thrift::protocol;  
using namespace ::apache::thrift::transport;  
using namespace ::apache::thrift::server;  
using namespace ::apache::thrift::concurrency;  

//using boost::shared_ptr;  
using std::shared_ptr;  

class UserServiceHandler : virtual public UserServiceIf {  
 public:  
  UserServiceHandler() {  
    // Your initialization goes here  
  }  

  void add(const User& u) {  
    // Your implementation goes here  
    printf("uid=%s uname=%s usex=%d uage=%d\n", u.uid.c_str(), u.uname.c_str(), u.usex, u.uage);  
  }  

  void get(User& _return, const std::string& uid) {  
    // Your implementation goes here  
    _return.uid = "sss";  
    _return.uname = "wei";  
    _return.usex = 1;  
    _return.uage = 22;  
    printf("uid=%s uname=%s usex=%d uage=%d\n", _return.uid.c_str(), _return.uname.c_str(), _return.usex, _return.uage);  
  }  

};  

int main(int argc, char **argv) {  
  shared_ptr<UserServiceHandler> handler(new UserServiceHandler());  
  shared_ptr<TProcessor> processor(new UserServiceProcessor(handler));  
  shared_ptr<TProtocolFactory> protocolFactory(new TCompactProtocolFactory());  
  shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());  
  shared_ptr<TServerTransport> serverTransport(new TServerSocket(9090));   
  shared_ptr<ThreadManager> threadManager = ThreadManager::newSimpleThreadManager(10);  
  shared_ptr<PosixThreadFactory> threadFactory = shared_ptr<PosixThreadFactory>(new PosixThreadFactory());  
  threadManager->threadFactory(threadFactory);  
  threadManager->start();  
  printf("start user server...\n");  

  TThreadPoolServer server(processor, serverTransport, transportFactory, protocolFactory, threadManager);  
  server.serve();  
  return 0;  
}  

注意这段代码使用TCompactProtocol,需要#include 另外这个是Blocking的多线程服务器

4.生成客户端文件UserClient.cpp
#include "UserService.h"  
#include <config.h>  
#include <transport/TSocket.h>  
#include <transport/TBufferTransports.h>  
#include <protocol/TCompactProtocol.h>  

using namespace apache::thrift;  
using namespace apache::thrift::protocol;  
using namespace apache::thrift::transport;  

using boost::shared_ptr;  

int main(int argc, char **argv) {  
        boost::shared_ptr<TSocket> socket(new TSocket(argv[1], 9090));  
        boost::shared_ptr<TTransport> transport(new TBufferedTransport(socket));  
        boost::shared_ptr<TProtocol> protocol(new TCompactProtocol(transport));  

        transport->open();  

        User u;  
        u.uid = "s";  
        u.uname = "w";  
        u.usex = 1;  
        u.uage = 22;  

        UserServiceClient client(protocol);  
        client.add(u);  

        User u1;  
        client.get(u1,"lll");  

        transport->close();  
        printf("uid=%s uname=%s usex=%d uage=%d\n", u1.uid.c_str(), u1.uname.c_str(), u1.usex, u1.uage);  
        return 0;  
}  
5.生成Makefile
BOOST_DIR = /usr/local/include/boost/  
THRIFT_DIR = /usr/local/include/thrift  
LIB_DIR = /usr/local/lib  
GEN_SRC = ./acsuser_types.cpp ./acsuser_constants.cpp ./UserService.cpp  
default: server client  
server: UserService_server.skeleton.cpp  
        g++ -g -o UserServer -I${THRIFT_DIR} -I${BOOST_DIR}  -I./gen-cpp -L${LIB_DIR} -lthrift UserService_server.skeleton.cpp ${GEN_SRC} -std=c++11
client: UserClient.cpp  
        g++ -g -o UserClient -lm -pthread -lz -lrt -lssl -I${THRIFT_DIR} -I${BOOST_DIR}  -I./gen-cpp -L${LIB_DIR} -lthrift UserClient.cpp ${GEN_SRC}  
clean:  
        $(RM) -r UserService_server.skeleton UserClient  
注:两台设备上都安装了服务端和客户端
6.在172.24.1.89上启动server
./UserServer  
7.在172.24.1.110上测试client
./UserClient
8.抓取报文
tcpdump -i en0 -nn -s0 port 9090 -w thrift.pcap -vvvv

这样就抓到了报文可以进行分析了。




遇到的问题及解决方法

    vim /etc/profile
    export PATH=/usr/local/bin:$PATH   //添加完重启设备即可
# vim /etc/ld.so.conf      //在新的一行中加入库文件所在目录
  /usr/lib  

# ldconfig                 //更新/etc/ld.so.cache文件