thrift

一 概念

Thrift框架是一个轻量级、跨语言、易部署的RPC框架。于2007年由FaceBook开发,2008年进入Apache开源项目。通过自身的IDL语言生成客户端和服务端的模板代码,使用者仅需要编写IDL语言则可使用。

二Thrift框架特点

1 开发速度快

编写RPC接口Thrift IDL文件则可通过编译生成器自动生成服务端骨架(Skeletons)和客户端桩(Stubs)。省去开发者自定义和维护接口编解码、消息传输、服务器多线程模型等工作。对于服务端来说只需要按服务骨架(接口),编写具体业务处理程序(Handler)实现类即可。而对于客户端,只要拷贝好IDL定义好的客户端桩和服务对象,就可以像调用本地方法一样进行远程调用。

2 接口维护简单

仅需维护Thrift格式的IDL(接口描述语言)则可作为客户端使用的接口文档,同时会自动根据IDL生成相对应的接口代码。

3 学习成本低

由Google Protobuf开发团队开发,IDL文件类似Google Protobuf。

4 跨语言支持

支持多种语言,包括C++、Python、Java等热门语言,同时客户端和服务端所使用的语言可以不一致。

5 稳定

有很多大型企业,如国外的Facebook,国内的百度、美团、小米等都在使用。

三thrift 使用

2 thfirt 双向通信

备注: 方案来自下面博客
https://zhuanlan.zhihu.com/p/397916864

2.1 方案

轮询
客户端周期性的向服务器请求是否需要进行某种操作,这种方案延迟较大且浪费开销。
双服务器双客户端
就是在服务器和客户端是相互,这种方案需要两个端口两者互为服务器和客户端。
异步共享通道(建立长链接)
Thrift底层实际上是socket,socket天然支持双向传输。我们完全可以通过继承Thrift类来满足我们的需求。

2.1
2.2 异步共享通道(建立长链接)

定义thrift接口

namespace cpp test
namespace py test
service HelloWorldBidirectionService{
    oneway void SayHello(1:string msg);
   oneway void test(1:string msg);
}
// 备注: 在实现双向thrift时接口的定义一定要是oneway,不然会报端口被强制关闭之类的错误。

服务端

#include <iostream>
#pragma comment(lib, "libthrift_d.lib")
#pragma comment(lib, "libthriftnb_d.lib")
#pragma comment(lib, "libcrypto32MTd.lib")
#pragma comment(lib, "libssl32MTd.lib")

// This autogenerated skeleton file illustrates how to build a server.
// You should copy it to another filename to avoid overwriting it.

#include "../testCommon/HelloWorldBidirectionService.h"
#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/server/TSimpleServer.h>
#include <thrift/transport/TServerSocket.h>
#include <thrift/transport/TBufferTransports.h>
#include <thrift/server/TThreadPoolServer.h>

#include <thrift/concurrency/ThreadManager.h>
#include <thrift/concurrency/ThreadFactory.h>  
#include <thrift/concurrency/Thread.h>

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

using namespace test;


static std::shared_ptr<TTransport> g_CurrentTransport = nullptr;

class HelloWorldBidirectionServiceHandler : virtual public HelloWorldBidirectionServiceIf {
public:
    HelloWorldBidirectionServiceHandler() {
        // Your initialization goes here
    }

    void SayHello(const std::string& msg) {
        // Your implementation goes here
        printf("%s\n", msg.c_str());
        std::string msgTmp = msg;
        msgTmp += " Server Send";
        SayToClient(msgTmp);
    }

    void test(const std::string& msg) {
        printf("test=%s", msg.c_str());
   }

    void SayToClient(const std::string& msg)
    {
        shared_ptr<TBinaryProtocol> protocol(new TBinaryProtocol(g_CurrentTransport));
        HelloWorldBidirectionServiceClient client(protocol);
        //Thread.Sleep(1000);
        client.SayHello(msg);
    }
};

class HelloWorldBidirectionProcessor : public TProcessorFactory
{
public:
    std::shared_ptr<TProcessor> getProcessor(const TConnectionInfo& connInfo)
    {
        g_CurrentTransport = connInfo.transport;

        printf("接收到连接信号\n");

        shared_ptr<HelloWorldBidirectionServiceHandler> handler(new HelloWorldBidirectionServiceHandler());
        shared_ptr<TProcessor> processor(new HelloWorldBidirectionServiceProcessor(handler));
        return processor;
    }
};

static std::shared_ptr<TProcessorFactory> getProcessorFactory()
{
    shared_ptr<TProcessorFactory> processorFactory(new HelloWorldBidirectionProcessor());
    return processorFactory;
}



int main(int argc, char** argv) {
    int port = 9090;
    shared_ptr<TServerTransport> serverTransport(new TServerSocket(port));
    shared_ptr<TTransportFactory> transportFactory(new TTransportFactory());
    shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());

    shared_ptr<ThreadManager> threadManager = ThreadManager::newSimpleThreadManager(10);//指定10个线程数  

    shared_ptr<ThreadFactory> threadFactory = shared_ptr<ThreadFactory>(new ThreadFactory());
    threadManager->threadFactory(threadFactory);
    threadManager->start();

    shared_ptr<TThreadPoolServer> server(new TThreadPoolServer(getProcessorFactory(), serverTransport, transportFactory, protocolFactory, threadManager));

    /* shared_ptr<HelloWorldBidirectionServiceHandler> handler(new HelloWorldBidirectionServiceHandler());
     shared_ptr<TProcessor> processor(new HelloWorldBidirectionServiceProcessor(handler));
     shared_ptr<TServerTransport> serverTransport(new TServerSocket(port));
     shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());
     shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());

     TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory);*/
    server->serve();
    return 0;
}

客户端代码

#include <iostream>

#pragma comment(lib, "libthrift_d.lib")
#pragma comment(lib, "libthriftnb_d.lib")
#pragma comment(lib, "libcrypto32MTd.lib")
#pragma comment(lib, "libssl32MTd.lib")

#include <iostream>

#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/transport/TSocket.h>
#include <thrift/transport/TTransportUtils.h>

#include "../testCommon/HelloWorldBidirectionService.h"

#include <thread>

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

using namespace test;

class HelloWorldBidirectionFace :public HelloWorldBidirectionServiceIf
{
public:
    void SayHello(const std::string& msg) {
        // Your implementation goes here
        /*printf("%s\n", msg);
        printf("%s\n", &msg);*/

        cout << msg << endl;
        //cout << &msg << endl;
    }

    void test(const std::string& msg) {
        printf("test=%s", msg.c_str());
    }
};

static void Run(std::shared_ptr<TTransport> sock)
{
    std::shared_ptr<HelloWorldBidirectionFace> handler(new HelloWorldBidirectionFace());
    std::shared_ptr<TProcessor> processor(new HelloWorldBidirectionServiceProcessor(handler));

    //boost::shared_ptr<HelloWorldBidirectionServiceProcessor> processor(new HelloWorldBidirectionFace());
    try
    {
        std::shared_ptr<TProtocol> inProtocol(new TBinaryProtocol(sock));
        std::shared_ptr<TProtocol> outProtocol(new TBinaryProtocol(sock));
        while (processor->process(inProtocol, outProtocol, (void*)"proc"))
        {
            printf("wait next msg\n");
        }
    }
    catch (TException& tx)
    {
        printf("connect close\n");
        cout << "ERROR1: " << tx.what() << endl;
    }
}

static void RecFromConsole(std::shared_ptr<HelloWorldBidirectionServiceClient> client)
{
    string str;
    cout << "input exit stop" << endl;
    cin >> str;
    while (str.compare("exit"))
    {
        client->SayHello(str);
        client->test("1122");
        cin >> str;
    }
}


int main()
{
    std::shared_ptr<TTransport> socket(new TSocket("localhost", 9090));
    std::shared_ptr<TTransport> transport(new TBufferedTransport(socket));
    std::shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));
    std::shared_ptr<HelloWorldBidirectionServiceClient> client(new HelloWorldBidirectionServiceClient(protocol));

    try {
        transport->open();

        std::thread mythread(Run, socket);

        std::thread mythread2(RecFromConsole, client);
        mythread2.join();

        transport->close();
    }
    catch (TException& tx) {
        cout << "ERROR: " << tx.what() << endl;
    }
}

四 thrift 编译

因thrift依赖boost、libevent、openssl、zlib,因此需要先编译这些库

1 windows VS2015编译

(1) vs2015编译boost
  1. 解压boost_1_75_0.7z到D:\soft,解压后路径为D:\soft\boost_1_75_0
  2. 在soft目录下创建boost_build文件夹;
  3. 开始菜单->visual studio 2015->VS2015 x86 x64 兼容工具命令提示符;
    注:编译64位的动态库使用该命令提示符工具,编译其他版本选择对应的命令提示符工具
  4. 在命令提示符工具中输入如下命令:
    cd D:\soft\boost_1_75_0
    bootstrap.bat
    b2 stage --toolset=msvc-14.0 architecture=x86 address-model=64 --without-graph --without-graph_parallel --stagedir=“D:\soft\boost_build” link=static runtime-link=shared runtime-link=static threading=multi debug release
  5. 编译需要10-30分钟,编译完成后,最终的boost库在D:\soft\boost_build下面;
  6. 将D:\soft\boost\include\boost-1_75\boost目录拷贝到D:\Program Files\boost_1_75_0\vs2015\x64\include目录下;
  7. 将D:\soft\boost_build\lib目录下的所有文件拷贝到D:\Program Files\boost_1_75_0\vs2015\x64\lib目录下;
(2) vs2015编译libevent
  1. 解压libevent-2.1.12-stable.tar.gz到D:\soft,解压后路径为D:\soft\libevent-2.1.12-stable;
  2. 记事本打开D:\soft\libevent-2.1.12-stable\minheap-internal.h,在文件头添加#include<stdint.h>
    注:如果不加该头文件,会报UINT32_MAX”未声明的标识符的错误
  3. 开始菜单->visual studio 2015->VS2015 x86 x64 兼容工具命令提示符;
    注:编译64位的动态库使用该命令提示符工具,编译其他版本选择对应的命令提示符工具
  4. 在命令提示符工具中输入如下命令:
    cd D:\soft\libevent-2.1.12-stable;
    nmake /f Makefile.nmake static_libs
    注:全量编译:nmake /f Makefile.nmake [all] //all可以省略,默认是all
    库编译: nmake /f Makefile.nmake static_libs
    测试编译:nmake /f Makefile.nmake tests
    清理输出:nmake /f Makefile.nmake clean
    编译完成,在D:\soft\libevent-2.1.12-stable目录下会生成 libevent.lib、libevent_core.lib和libevent_extras.lib动态库;
  5. 将生成的3个动态库拷贝到D:\Program Files\libevent-2.1.12-stable\vs2015\x64\lib目录下;
  6. 将D:\soft\libevent-2.1.12-stable\include目录拷贝到D:\Program Files\libevent-2.1.12-stable\vs2015\x64\include;
  7. 将D:\soft\libevent-2.1.12-stable\WIN32-Code\nmake\event2\event-config.h文件拷贝到D:\Program Files\libevent-2.1.12-stable\vs2015\x64\include\event2目录下;
(3) openssl 编译

openssl使用的版本是 openssl-1.1.1 可以下载也可以自己编译

(4) thrift 编译
  1. 将D:\soft\thrift-0.14.1\config.h文件拷贝到D:\soft\thrift-0.14.1\lib\cpp\src\thrift目录下;不然在编译的时候会报找不到<thrift/config.h>文件;
  2. 修改拷贝过去的config.h文件,将所有HAVE开头的宏都注释掉;
  3. 使用vs2015打开D:\soft\thrift-0.14.1\lib\cpp\thrift.sln解决方案文件;
  4. 打开后可以看到libthrift和libthriftnb两个工程,这里我们编译libthrift即可
    注:libthriftnb工程是非阻塞(non-blocking)模式的服务器,非阻塞模式需要依赖libevent库;(实际编译情况来看libthrift也依赖libevent库)
  5. 增加依赖的库和头文件
  6. 编译

2 国产编译

(1)编译libevent
// 编译mac
./configure --prefix=/Users/admin/xhw/thrift/3rd/libevent/mac
// 编译x86——64
./configure  --disable-openssl  --prefix=/root/xhw/thrift/compile/3rd/libevent/x86_64
// 交叉编译aarch64 libevent库 
./configure --prefix=/root/xhw/thrift/compile/3rd/libevent/aarch64 --host=arm-linux CC=/root/cross-compile/sdk/aarch64/usr/bin/aarch64-linux-gcc  CXX=/root/cross-compile/sdk/aarch64/usr/bin/aarch64-linux-g++
// 交叉编译loongarch64 libevent库
./configure --prefix=/root/xhw/thrift/compile/3rd/libevent/loongarch   --host=arm-linux       CC=/root/cross-compile/node/loongarch64/node_build_loongarch64/bin/loongarch64-linux-gnu-gcc CXX=/root/cross-compile/node/loongarch64/node_build_loongarch64/bin/loongarch64-linux-gnu-g++
(2) 编译boost库
// x86_64
./bootstrap.sh --with-libraries=all --with-toolset=gcc
./b2 install --prefix=/root/xhw/thrift/compile/3rd/boost/x86_64

// mac
./bootstrap.sh --with-libraries=all --with-toolset=gcc
./b2 install --prefix=/Users/admin/xhw/thrift/3rd/boost/mac

// 交叉编译 aarch64
./bootstrap.sh --with-libraries=all --with-toolset=gcc
//修改 配置文件project-config.jam
if ! gcc in [ feature.values <toolset> ]
{
    using gcc : arm :/root/cross-compile/sdk/aarch64/usr/bin/aarch64-linux-gcc
}
./b2
./b2 install --prefix=/root/xhw/thrift/compile/3rd/boost/aarch64

// 交叉编译loongarch
./bootstrap.sh --with-libraries=all --with-toolset=gcc
// 修改 配置文件project-config.jam
if ! gcc in [ feature.values <toolset> ]
{
    using gcc : arm :/root/cross-compile/node/loongarch64/node_build_loongarch64/bin/loongarch64-linux-gnu-gcc
}
./b2
./b2 install --prefix=/root/xhw/thrift/compile/3rd/boost/loongarch
(3) 编译thrift库

thriftBuild.sh

#! /bin/bash
# openssl安装目录
export OPENSSL_DIR="/root/xhw/thrift/compile/3rd/openssl/x86_64"
# boost安装目录
export BOOST_ROOT="/root/xhw/thrift/compile/3rd/boost/x86_64"
# libevent安装目录
export LIBEVENT_DIR="/root/xhw/thrift/compile/3rd/libevent/x86_64"
export CC=gcc
export CXX=g++
./configure CXXFLAGS="-fPIC" CFLAGS="-fPIC" --prefix=/root/xhw/thrift/compile/3rd/thrift/x86_64 \
    --disable-tests \
	--enable-shared \
    --disable-tutorial \
    --with-cpp \
    --without-python \
    --without-java \
    --without-lua \
    --without-perl \
    --with-c_glib \
    --enable-static \
    --with-boost=${BOOST_ROOT} \
    --with-libevent=${LIBEVENT_DIR} \
#	--with-openssl=${OPENSSL_DIR}
    --without-openssl
#    --enable-libs=no

thriftBuildAarch64.sh

#! /bin/bash
# openssl安装目录
export OPENSSL_DIR="/root/xhw/thrift/compile/3rd/openssl/aarch64"
# boost安装目录
export BOOST_ROOT="/root/xhw/thrift/compile/3rd/boost/aarch64"
# libevent安装目录
export LIBEVENT_DIR="/root/xhw/thrift/compile/3rd/libevent/aarch64"
export CC=/root/cross-compile/sdk/aarch64/usr/bin/aarch64-linux-gcc
export CXX=/root/cross-compile/sdk/aarch64/usr/bin/aarch64-linux-g++
export LDFLAGS="-L$OPENSSL_DIR/lib"
./configure CXXFLAGS="-fPIC" CFLAGS="-fPIC"   --prefix=/root/xhw/thrift/compile/3rd/thrift/aarch64 --host=x86_64 --target=aarch64 \
    --disable-tests \
    --disable-shared \
    --disable-tutorial \
    --with-cpp \
    --without-python \
    --without-java \
    --without-lua \
    --without-perl \
    --with-c_glib \
    --enable-static \
    --with-boost=${BOOST_ROOT} \
    --with-libevent=${LIBEVENT_DIR} \
	--with-ssl=${OPENSSL_DIR}

3 编译错误

(1) 错误一
depbase=`echo src/thrift/TApplicationException.lo | sed 's|[^/]*$|.deps/&|;s|\.lo$||'`;\
/bin/bash ../../libtool  --tag=CXX   --mode=compile /root/cross-compile/sdk/aarch64/usr/bin/aarch64-linux-g++ -std=c++11 -DHAVE_CONFIG_H -I. -I../.. -I../../lib/cpp/src/thrift -I../../lib/c_glib/src/thrift  -I/root/xhw/thrift/compile/3rd/boost/aarch64/include  -I./src -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS  -Wall -Wextra -pedantic -g -O2 -MT src/thrift/TApplicationException.lo -MD -MP -MF $depbase.Tpo -c -o src/thrift/TApplicationException.lo src/thrift/TApplicationException.cpp &&\
mv -f $depbase.Tpo $depbase.Plo
libtool: compile:  /root/cross-compile/sdk/aarch64/usr/bin/aarch64-linux-g++ -std=c++11 -DHAVE_CONFIG_H -I. -I../.. -I../../lib/cpp/src/thrift -I../../lib/c_glib/src/thrift -I/root/xhw/thrift/compile/3rd/boost/aarch64/include -I./src -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -Wall -Wextra -pedantic -g -O2 -MT src/thrift/TApplicationException.lo -MD -MP -MF src/thrift/.deps/TApplicationException.Tpo -c src/thrift/TApplicationException.cpp -o src/thrift/TApplicationException.o
In file included from /root/cross-compile/sdk/aarch64/usr/aarch64-buildroot-linux-gnu/include/c++/5.4.0/ext/string_conversions.h:41:0,
                 from /root/cross-compile/sdk/aarch64/usr/aarch64-buildroot-linux-gnu/include/c++/5.4.0/bits/basic_string.h:5249,
                 from /root/cross-compile/sdk/aarch64/usr/aarch64-buildroot-linux-gnu/include/c++/5.4.0/string:52,
                 from ./src/thrift/Thrift.h:37,
                 from ./src/thrift/TApplicationException.h:23,
                 from src/thrift/TApplicationException.cpp:20:
/root/cross-compile/sdk/aarch64/usr/aarch64-buildroot-linux-gnu/include/c++/5.4.0/cstdlib:140:11: error: '::malloc' has not been declared
   using ::malloc;
           ^
/root/cross-compile/sdk/aarch64/usr/aarch64-buildroot-linux-gnu/include/c++/5.4.0/cstdlib:153:11: error: '::realloc' has not been declared

解决方式

解决方式:  进入到/root/xhw/thrift/compile/thrift-0.12.0/lib/cpp/src/thrift目录,注释掉config.h目录中的
#define malloc rpl_malloc
#define realloc rpl_realloc
(2) 错误二

在这里插入图片描述
解决方式

./config.h /lib/cpp/src/thrift/config.h (如果c_glib也出现 /lib/c_glib/src/thrift/config.h) 中加入宏
#define SIGNED_RIGHT_SHIFT_IS 1
#define ARITHMETIC_RIGHT_SHIFT 1
(3)错误三
src/thrift/TOutput.cpp:110:22: error: invalid conversion from 'char*' to 'int' [-fpermissive]
   int rv = strerror_r(errno_copy, b_errbuf, sizeof(b_errbuf));

解决方式

 在TOutput.cpp:110:22 行函数前面加 
 #define STRERROR_R_CHAR_P 1
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值