Qt中调用thrift

Posted 草上爬

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Qt中调用thrift相关的知识,希望对你有一定的参考价值。

thrift是一个Apache公司开源的一款RPC(Remote Procedure Call)框架,让不同语言构建的服务可以做到远程调用无缝对接。
thrift库分两部分:
libthrift - 核心库文件,需要依赖OpenSSL、boost
libthriftnb - 包含thrift非阻塞服务器, 需要libevent
编译环境
操作系统:windows 10
Qt:5.12.10 MinGW64
这里因为项目需要,编译MinGW64版本的thrift。Qt安装完成后将下列路径添加到环境变量:
D:\\Qt\\Qt5.12.10\\Tools\\mingw730_64\\bin
D:\\Qt\\Qt5.12.10\\5.12.10\\mingw73_64\\bin

一.MingW64编译boost

boost1.81.0

1.生成编译工具

加压boost源码,cmd中输入

bootstrap.bat gcc

表示使用“gcc”工具集(即我们安装的64位MingW)生成编译工具“b2.exe”

2.编译并安装boost

b2.exe install --build-type=complete threading=multi link=static address-model=64 toolset=gcc

stage表示只生成库(dll和lib),install还会生成包含头文件的include目录;
--build-type=complete表示同时生成Debug和Release版本;
threading=multi表示线程方式使用“multi ”(多线程);
link=static表示编译成静态库,shared表示编译成动态库;
address-model=64表示地址模型使用64位(即生成的库均为64位库);
toolset=gcc表示工具集使用“gcc”
可以使用b2.exe --help查看所有参数,可通过--prefix="XXXXXX"指定安装位置,如果不指定位置,默认安装到C:\\Boost

二.MingW64编译OpenSSL

OpenSSL1.1.1q
下载安装msys2,我选的是最新的msys2-x86_64-20221216.exe,默认安装到C:\\msys64
msys2是一个模拟的Linux命令行开发环境。msys2里本身就带了mingw,如果要用自己开发环境的mingw(也就是Qt自带的mingw,前面已添加到windows环境变量)。这里还需要在windows系统变量中创建一个变量MSYS2_PATH_TYPE,值为inherit,msys2就会继承windows系统的环境变量,去找寻windows中已经配置好的mingw工具。重新打开MSYS2 MSYS,输入gcc,没有提示找不到文件就说明刚设置的变量生效了。

如果要使用msys2自带的mingw,需要打开MSYS2 MINGW32或MSYS2 MINGW64。

经测试,这两种方式编译的OpenSSL都能正常使用。
.pro文件中添加

INCLUDEPATH += C:\\msys64\\home\\openssl-1.1.1q\\mingw64\\include

LIBS += C:\\msys64\\home\\openssl-1.1.1q\\mingw64\\lib\\libcrypto.a \\
        C:\\msys64\\home\\openssl-1.1.1q\\mingw64\\lib\\libssl.a

LIBS += -lWs2_32 -lCrypt32

注意要添加Ws2_32和Crypt32这两个windows库,否则很多函数找不到
下载OpenSSL,解压到C:\\msys64\\home\\

1.配置

在openssl-1.1.1q新建mingw64文件夹,用来存放安装的文件
打开MSYS2 MINGW64,输入

cd C:/msys64/home/openssl-1.1.1q
./configure mingw64 no-shared --prefix="C:/msys64/home/openssl-1.1.1q/mingw64"

默认编译的是动态库,这里指定no-shared生成静态库
我这正常。这一步如果提示缺少perl,“/usr/bin/perl:bad interpreter:No such file or directory”,可以用指令pacman -S perl安装一个。

2.编译

make

如果提示“-bash: make: command not found”,可以用指令pacman -S make安装一个

3.安装

make install


刚进行到这一步,突然发现boost和OpenSSL可以直接安装.......,上面的内容请忽略
分割线***************************************************************************
这里是官方用MSYS2编译thrift的参考链接:https://github.com/apache/thrift/blob/master/build/cmake/README-MSYS2.md
明确指出通过这种编译方式无法生成非阻塞的服务器类型,因为libevent无法正常工作。
Note: libevent and libevent-devel do not work with this toolchain as they do not properly detect mingw64 and expect some headers to exist that do not, so the non-blocking server is not currently built into this solution.
因此,thrift传输层中的TNonblockingTransport和服务端类型中的TNonblockingServer都无法使用

thrift的协议(应用层
thrift可以让用户选择客户端与服务端之间传输通信协议的类别,在传输协议上总体划分为文本(text)和二进制(binary)传输协议。为节约带宽,提高传输效率,一般情况下使用二进制类型的传输协议为多数,有时还会使用基于文本类型的协议,这需要根据项目/产品中的实际需求。常用协议有以下几种:
TBinaryProtocol:二进制编码格式进行数据传输
TCompactProtocol:高效率的、密集的二进制编码格式进行数据传输 (常用的)
TJSONProtocol: 使用JSON文本的数据编码协议进行数据传输
TSimpleJSONProtocol:只提供JSON只写的协议,适用于通过脚本语言解析
thrift的传输层
TSocket:使用阻塞式I/O进行传输,是最常见的模式
TNonblockingTransport:使用非阻塞方式,用于构建异步客户端
TFramedTransport:使用非阻塞方式,按块的大小进行传输,类似于Java中的NIO
thrift的服务端类型
TSimpleServer:单线程服务器端,使用标准的阻塞式I/O
TThreadPoolServer:多线程服务器端,使用标准的阻塞式I/O
TNonblockingServer:单线程服务器端,使用非阻塞式I/O
THsHaServer:半同步半异步服务器端,基于非阻塞式IO读写和多线程工作任务处理
TThreadedSelectorServer:多线程选择器服务器端,对THsHaServer在异步IO模型上进行增强

一.安装编译环境

打开MSYS2 MINGW64,输入

pacman --needed -S bison flex make mingw-w64-x86_64-openssl \\
                 mingw-w64-x86_64-boost mingw-w64-x86_64-cmake \\
                 mingw-w64-x86_64-toolchain mingw-w64-x86_64-zlib

下载thrift源码,我选择的是最新的thrift-0.17.0,解压到C:\\msys64\\home

注:thrift-0.17.0.exe也要下载,然后重名为thrift.exe并添加到环境变量,待会需要用它将IDL文件转换成cpp源文件

cd C:/msys64/home/thrift-0.17.0
mkdir ../thrift-build
cd ../thrift-build
mkdir ../thrift-build
cd ../thrift-build
cmake -G"MinGW Makefiles" -DCMAKE_MAKE_PROGRAM=/mingw64/bin/mingw32-make \\
   -DCMAKE_C_COMPILER=x86_64-w64-mingw32-gcc.exe \\
   -DCMAKE_CXX_COMPILER=x86_64-w64-mingw32-g++.exe \\
   -DWITH_LIBEVENT=OFF \\
   -DWITH_SHARED_LIB=OFF -DWITH_STATIC_LIB=ON \\
   -DWITH_JAVA=OFF -DWITH_PYTHON=OFF -DWITH_PERL=OFF \\
   ../thrift-0.17.0

二.编译

cmake --build .

编译成功,但是会有一个依赖NodeJS的错误,如下图所示。该错误不影响使用,因为所有的test都能测试通过。

三.运行测试

ctest

四.安装

cmake --install .

默认安装到C:\\Program Files (x86)\\thrift,这一步需要管理员权限,因此得用管理员权限打开MSYS2 MINGW64

五.一个例子

1.编写.thrift文件,生成cpp文件

新建文件student.thrift,输入如下内容

struct Student
    1: i32 sno,
    2: string sname,
    3: bool ssex,
    4: i16 sage,

service CaoShangPa
    void put(1: Student s),

打开cmd,进入student.thrift文件所在目录,执行如下命令

thrift -r --gen cpp student.thrift

生成如下5个文件
student_types.h
student_types.cpp
CaoShangPa.h
CaoShangPa.cpp
CaoShangPa_server.skeleton.cpp
其中CaoShangPa_server.skeleton.cpp是一个简单的服务端demo

2.客户端

在Qt中新建控制台工程Thrift_Client,将上面的除CaoShangPa_server.skeleton.cpp外的四个文件添加到工程中,main.cpp修改为如下所示

#include "CaoShangPa.h"
#include <thrift/transport/TSocket.h>
#include <thrift/transport/TBufferTransports.h>
#include <thrift/protocol/TBinaryProtocol.h>
#include <iostream>
using namespace apache::thrift;
using namespace apache::thrift::protocol;
using namespace apache::thrift::transport;

//using boost::shared_ptr;

int main(int argc, char **argv) 
    std::shared_ptr<TSocket> socket(new TSocket("127.0.0.1", 9090));
    std::shared_ptr<TTransport> transport(new TBufferedTransport(socket));
    std::shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));
    transport->open();

    Student s;
    s.sno = 123;
    s.sname = "gavin";
    s.ssex = 1;
    s.sage = 30;
    CaoShangPaClient client(protocol);
    std::cout<<"Client send a data"<<std::endl;
    std::cout<<"no:123"<<std::endl;
    std::cout<<"name:gavin"<<std::endl;
    std::cout<<"sex:1"<<std::endl;
    std::cout<<"age:30"<<std::endl;
    client.put(s);

    transport->close();
    return 0;

3.服务端

在Qt中新建控制台工程Thrift_Server,将上面的除CaoShangPa_server.skeleton.cpp外的四个文件添加到工程中,main.cpp修改为如下所示

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

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

class CaoShangPaHandler : virtual public CaoShangPaIf 
public:
    CaoShangPaHandler() 
        // Your initialization goes here
    

    void put(const Student& s) 
        // Your implementation goes here
        std::cout<<"Server receive a data"<<std::endl;
        std::cout<<"no:"<<s.sno<<std::endl;
        std::cout<<"name:"<<s.sname<<std::endl;
        std::cout<<"sex:"<<s.ssex<<std::endl;
        std::cout<<"age:"<<s.sage<<std::endl;
    
;

int main(int argc, char **argv) 
    std::cout<<"Server started!"<<std::endl;
    int port = 9090;
    ::std::shared_ptr<CaoShangPaHandler> handler(new CaoShangPaHandler());
    ::std::shared_ptr<TProcessor> processor(new CaoShangPaProcessor(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();
    return 0;

4.pro文件配置

Thrift_Client.pro和Thrift_Server.pro中都要添加如下内容

INCLUDEPATH += "C:\\Program Files (x86)\\thrift\\include" #路径中有空格要加引号
INCLUDEPATH += C:\\Boost\\include\\boost-1_81

LIBS += -L"C:\\Program Files (x86)\\thrift\\lib" -lthrift
LIBS += -lWs2_32

我这编译的时候会报错
C:\\Program Files (x86)\\thrift\\include\\thrift\\windows\\config.h:79: error: afunix.h: No such file or directory
解决方法
打开config.h,将#ifdef HAVE_AF_UNIX_H改成#ifndef HAVE_AF_UNIX_H

5.运行

先运行Thrift_Server,再运行Thrift_Client,结果如下所示

原文链接:https://blog.csdn.net/caoshangpa/article/details/128474421

以上是关于Qt中调用thrift的主要内容,如果未能解决你的问题,请参考以下文章

Qt基础之二十一:QtRO(Qt Remote Object)实现进程间通信

带有 Thrift 和 Qt 的简单服务器

如何安装 Thrift 以使用 Qt-Windows

框架|Thrift 探秘

RPC框架实践之:Apache Thrift

RPC框架实践之:Apache Thrift