thrift在windows系统下C++环境搭建/QT使用(记录,踩坑合集)

thrift在windows系统下C++环境搭建/QT使用(记录,踩坑合集)

1. 依赖库

thrift的编译依赖第三方库(boost、libevent、openssl)
采用第一种编译方法可暂时不下载依赖库!!!,这里也更推荐第一种编译方法,可以省略很多麻烦的编译过程,boost是必须编译的,因为c++和qt也需要单独引用。

boost

可以从boost官网上下载boost库。
个人经历,推荐下载1_72_0,不要使用1_74_0,某些资料里说74版本在windows下有未知bug,尚不完善。我自己下载了74,在qt内引入使用时缺少了部分hpp文件,所以重新下载了72版本。
下载后解压,运行bootstrap.bat文件,会在当前目录下生成b2.exe。
编译命令: 参数含义以及配置可以参考boost编译参数

1.71.0开始,bjam由b2代替
msvc-14.1代表vs2017

b2 stage --toolset=msvc-14.1 --without-python link=static runtime-link=shared runtime-link=static threading=multi debug release 

其中版本参考

MSVC++ 4.x  _MSC_VER == 1000
MSVC++ 5.0  _MSC_VER == 1100
MSVC++ 6.0  _MSC_VER == 1200
MSVC++ 7.0  _MSC_VER == 1300
MSVC++ 7.1  _MSC_VER == 1310 (Visual Studio 2003)
MSVC++ 8.0  _MSC_VER == 1400 (Visual Studio 2005)
MSVC++ 9.0  _MSC_VER == 1500 (Visual Studio 2008)
MSVC++ 10.0 _MSC_VER == 1600 (Visual Studio 2010)
MSVC++ 11.0 _MSC_VER == 1700 (Visual Studio 2012)
MSVC++ 12.0 _MSC_VER == 1800 (Visual Studio 2013)
MSVC++ 14.0 _MSC_VER == 1900 (Visual Studio 2015)
MSVC++ 14.1 _MSC_VER == 1911 (Visual Studio 2017) 

大概十几分钟(慢的话半小时?)编译完成,在当前目录下生成stage目录,即为编译后的文件,之后可以作为外部库被引用,boost文件夹和使用编译命令的install产生的hpp相同也会被作为外部依赖被引入,所以不采用install方式。
在这里插入图片描述

libevent

libthrift工程和libthriftnb工程。前者为阻塞的,后者为非阻塞模式的服务器,非阻塞模式的服务器需要libevent库。
我们使用的是libthrift,可以暂时不安装libevent库。
下载地址:https://libevent.org

openssl

下载Win64OpenSSL_Light-1_1_0f.exeWin64OpenSSL- 1_1_0f.exe,可以选择安装后者,前者是轻量级的不含源码的目标文件。
下载地址可选:
http://slproweb.com/products/Win32OpenSSL.html
https://oomake.com/download/openssl
如果想自行编译,具体细节可参考此博文

2. 编译过程

首先需要下载thrift源码以及windows下可执行程序,官网最新版本是thrift-0.13.0,但是windows下的版本有比较多的问题,所以推荐使用thrift-0.12.0版本。其中tar.gz用于编译,exe用来直接生成目标语言的代码。
在这里插入图片描述
解压tar.gz,thrift的c++编译需要打开.sln文件,目录是 xx\thrift\thrift-0.12.0\lib\cpp下的thrift.sln,使用VS2017打开(本机装的是VS2017)进行编译。

(1) 使用VS2017内置插件库编译

编译libthrift工程和libthriftnb工程。前者为阻塞的,后者为非阻塞模式的服务器,非阻塞模式的服务器需要libevent库。
VS2017 VS自带的Nuget安装boost、libevent、openssl 然后编译,我们这里选择x64的编译器。
菜单栏—工具—NuGet包管理器—管理解决方案的NuGet程序包,分别搜索上述3个库(版本可参考下面截图)并安装(可以全局安装也可以只为libthrift安装),安装完之后会在xx:\thrift\thrift-0.12.0\lib\cpp下的packages目录找到这些依赖。
然后在libthrift项目中引入依赖,不引入的话,会报很多hpp文件No such file or directory的错误。

右键libthrift—属性
在这里插入图片描述
此处将依赖库引入项目,选择packages下的对应依赖库即可。
在这里插入图片描述
代码引入方式(会自动生成),选择文件请参考下图路径

D:\Apache\thrift\thrift-0.12.0\lib\cpp\packages\libevent_vc120.2.1.4.0\build\native\include
D:\Apache\thrift\thrift-0.12.0\lib\cpp\packages\boost.1.72.0.0
D:\Apache\thrift\thrift-0.12.0\lib\cpp\packages\openssl-vc141-static-x86_64.1.1.0\build\native\include
%(AdditionalIncludeDirectories)

在这里插入图片描述
代码引入(自行生成),选择文件请参考下图路径

D:\Apache\thrift\thrift-0.12.0\lib\cpp\packages\openssl-vc141-static-x86_64.1.1.0
D:\Apache\thrift\thrift-0.12.0\lib\cpp\packages\boost.1.72.0.0
%(AdditionalLibraryDirectories)

引入之后点击生成开始编译,可能会报如下错误:

\thttpclient.cpp(25): fatal error C1083: 无法打开包括文件: “thrift/config.h”: No such file or directory

是因为没有正常生成config.h文件。可以自己手动写一个,放到xx:\thrift\thrift-0.12.0\lib\cpp\src\thrift目录下,内容如下

#include <stdlib.h>
#include <string.h>
 
#define PACKAGE_VERSION "0.12.0"

重新编译生成即可,成功之后会在cpp文件夹下生成x64文件夹,即为编译后的thrift,qt或c++需要引入的是xx:\thrift\thrift-0.12.0\lib\cpp\x64\Debug目录下的libthrift.lib !!!。
thrift到此编译成功。

(2) 自行加载库进行编译

将libthrift的依赖库修改为自己编译的目录,但是可能会存在很多不适配的问题,所以不推荐。
最终也会生成上面的libthrift.lib

3. 服务器和客户端开发实例

(1) 生成接口文件

使用前面下载的thrift-0.12.0.exe(建议修改为thrift.exe)来生成对应语言的接口文件
在thrift-0.12.0.exe同级目录手写add.thrift(这里我们就以a+b作为例子,客户端发送a和b,服务器端计算并返回结果)

//add.thrift
//a + b

service AddService{ 
	i32 add(1: i32 num1, 2: i32 num2)
}

编译命令

thrift -r --gen cpp add.thrift

生成文件gen-cpp,其中含有AddService_server.skeleton.cpp为服务器框架。
在这里插入图片描述

(2) C++环境下使用/QT creator

这里我们使用QT creator来实现,新建QT项目,选择64bit,将gen-cpp下的.cpp和.h都引用进来。
C++同理,只需要下面的client和server代码即可。
在这里插入图片描述
在xxx.pro中引入依赖库,boost和thrift

INCLUDEPATH += D:\Apache\thrift\boost_1_72_0
INCLUDEPATH += D:\Apache\thrift\thrift-0.12.0\lib\cpp\src

LIBS += -LD:\Apache\thrift\boost_1_72_0\stage\lib  //目录
LIBS += D:\Apache\thrift\thrift-0.12.0\lib\cpp\x64\Debug\libthrift.lib

client.cpp

#include "AddService.h"
#include <thrift/transport/TSocket.h>
#include <thrift/transport/TBufferTransports.h>
#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/server/TSimpleServer.h>
#include <thrift/transport/TServerSocket.h>
//#include <thrift/transport/TBufferTransports.h>

using namespace apache::thrift;
using namespace apache::thrift::protocol;
using namespace apache::thrift::transport;
using std::shared_ptr;
#include <iostream>

int addAandB()
{
    shared_ptr<TSocket> socket(new TSocket("127.0.0.1",9090)); //端口自定义
    shared_ptr<TTransport> transport(new TBufferedTransport(socket));
    shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));
    AddServiceClient client(protocol);
    try
    {
        transport->open();
    }
    catch(TTransportException)
    {
        transport->close();
    }
    std::int32_t res;
    res = client.add(1, 2);
    std::cout<<res<<std::endl;
    return res;
}

client.h

#ifndef CLIENT_H
#define CLIENT_H


class client
{
public:
    client();
};

int addAandB();

#endif // CLIENT_H

server.cpp
thrift已经给我们生成了一个服务器端实例(AddService_server.skeleton.cpp),修改一下即可用

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

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

class AddServiceHandler : virtual public AddServiceIf {
 public:
  AddServiceHandler() {
    // Your initialization goes here
  }
  int32_t add(const int32_t num1, const int32_t num2) {
    // Your implementation goes here
    printf("add\n");
    return (num1 + num2);
  }

};

void startServer(){
    int port = 9090;
    ::std::shared_ptr<AddServiceHandler> handler(new AddServiceHandler());
    ::std::shared_ptr<TProcessor> processor(new AddServiceProcessor(handler));
    ::std::shared_ptr<TServerTransport> serverTransport(new TServerSocket(port));
    ::std::shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());
    ::std::shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());

    TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory);
    server.serve();

}

server.h

#ifndef SERVER_H
#define SERVER_H


class server
{
public:
    server();
};

void startServer();

#endif // SERVER_H

由于本文只需要验证环境搭建,所以只考虑运行成功,不考虑线程问题,具体客户端和服务器端实现,可重新构建。
其中客户端和服务器端可以使用任何语言实现,只要对应端口相同即可调用,这也就实现了thrift的跨语言调用和交互
thrift在java环境下的实现下一篇继续。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

anjushi_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值