1. 简介
Apache Thrift软件框架(用于可扩展的跨语言服务开发)将软件堆栈与代码生成引擎结合在一起,它有自己的跨机器的通信框架,并提供一套库。它是一个代码生成器,按照它的规则,可以生成多种编程语言(C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell,C#, Cocoa,JavaScript,Node.js,Smalltalk,OCaml和Delphi等语言)的通讯过程代码。
简单说就是支持跨语言跨平台通信。比如服务器和客户端通信,但是两端用的平台和编程语言都不一样,就可以用thrift轻松解决。
那它是怎么解决跨语言通信的呢?至于技术本身原理这里不深挖了,只写用户需要做什么。对于用户而言,只需写一个*.thrift文件,定义通信数据(如结构体)和函数。举个简单例子,在服务器上我们实现了一个计算器的功能,在客户端需要给出计算的数字和符号。那么计算器函数接口和参数都需要在 *.thrift文件中定义,然后在服务器和客户端分别用thrift的命令行生成对应语言的函数。具体的见后文。
下面我们开始安装并使用吧~
2. 开始
2.1 下载
Ubuntu下载后进入下载目录,利用tar -zxvf命令解压
tar -zxvf thrift-0.13.0.tar.gz
(注:我没有使用镜像资源,而是git clone了源码,因为镜像编译不过去,但是git下来的就不会报一堆奇奇怪怪的错误)
git clone https://github.com/apache/thrift.git
cd thrift
Windows需要下载.exe文件,可以不用下源码。exe本身就是编译好给windows用户使用的。
2.2 编译并安装Apache Thrift编译器
2.2.1 安装依赖环境(C++)
sudo apt-get install automake bison flex g++ git libboost-all-dev libevent-dev libssl-dev libtool make pkg-config
如果用其他语言,安装相关库(这里只列常用,其他参考官网)
- Java
packages: gradle
JDK v1.8或以上版本.
apt-get install default-jdk
- Python
python-all
python-all-dev
python-all-dbg - Php, install
php5-dev
php5-cli
phpunit
2.2.2 编译
第一次从源码编译,需要生成配置脚本。
./bootstrap.sh
配置thrift
./configure
其他配置选项可以使用help查看
./configure --help
make
make -j16
测试(可省略)
make check
sh test/test.sh
如果你只看安装教程,请坚持看到2.2.4,到这里还没安装完呢。
2.2.3 编译报错情况
- “compiler/cpp/thriftl.cc:2190: undefined reference to `yywrap’”
安装 Flex library,然后重新配置
- mv: cannot stat “’.deps/TBinaryProtocol.Tpo’: No such file or directory” while building the Thrift Runtime Library
重新配置
./configure --enable-libtool-lock
或者
make -j 1
2.2.4 安装
sudo make install
最好make和make install都在sudo下执行,否则会报权限不足错误。
2.3 编写.thrift文件
下面可以开始使用thrift了。一切都要从编写thrift文件开始。该文件是定义thrift类型(参数)和服务(函数)的接口。其中服务是指在服务端实现,被客户端调用的函数。thrift编译器用于将thrift文件生成不同语言的源码。
使用thrift编译器生成源码的命令格式:
thrift --gen <language> <Thrift filename>
关于thrift更多内容可以参考文章Thrift: Scalable Cross-Language Services Implementatio
3. 例子
3.1 目标
实现加法计算。
3.2 calculator.thrift
service CalculatorService {
i32 add(1:i32 num1, 2:i32 num2),
}
然后命令行进入.thrift目录下,执行
thrift -r --gen cpp calculator.thrift
命令执行完会生成gen-cpp文件夹,里面包含7个文件
其中skeleton是一个服务端框架,需要自己实现;
我们用到的大部分内容都在Service里。
3.3 服务端-Calculator-server.cpp
将CalculatorService_server.skeleton.cpp拷贝出来,更改名称为calculator-server.cpp,并修改add函数
int32_t add(const int32_t num1, const int32_t num2) {
// Your implementation goes here
return num1+num2;
printf("add\n");
}
并修改包含目录
#include "./gen-cpp/CalculatorService.h"
3.4 客户端-Calculator-client.cpp
将Calculator-server.cpp拷贝修改文件名为Calculator-client.cpp,并修改code如下:
// This autogenerated skeleton file illustrates how to build a server.
// You should copy it to another filename to avoid overwriting it.
#include "./gen-cpp/CalculatorService.h"
#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/transport/TSocket.h>
#include <thrift/transport/TTransportUtils.h>
#include <iostream>
using namespace ::apache::thrift;
using namespace ::apache::thrift::protocol;
using namespace ::apache::thrift::transport;
using namespace std;
int main(int argc, char **argv) {
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));
CalculatorServiceClient client(protocol);
try
{
transport->open();
int result, addarg1, addarg2;
while(1)
{
cout << "please input arg1:";
cin >> addarg1;
cout << "please input arg2:";
cin >> addarg2;
result = client.add(addarg1, addarg2);
cout << "result is :" << result << endl;
transport->close();
}
// transport->close();
}
catch (TException &tx)
{
cout << "ERROR: " << tx.what() << endl;
}
}
3.5 CMakeLists.txt
可以通过vscode创建cmakelists。通过Ctrl + Shift + P 来打开命令行,输入cmake然后选择CMake:Quick Start
cmake_minimum_required(VERSION 3.0.0)
# 寻找Boost库
# find_package(Boost REQUIRED)
# include_directories(SYSTEM "${Boost_INCLUDE_DIRS}")
set(Thrift_DIR /home/dreamdeck/Downloads/thrift/build/cmake)
set(CMAKE_MODULE_PATH ${Thrift_DIR})
include(BoostMacros)
REQUIRE_BOOST_HEADERS()
# 寻找thrift
include(ThriftMacros)
#Make sure gen-cpp files can be included
include_directories("${CMAKE_CURRENT_BINARY_DIR}")
include_directories("${CMAKE_CURRENT_BINARY_DIR}/gen-cpp")
include_directories("${PROJECT_SOURCE_DIR}/lib/cpp/src")
# include(ThriftMacros)
# 源码集合
set(calculatorgencpp_SOURCES
gen-cpp/CalculatorService.cpp
gen-cpp/calculator_constants.cpp
gen-cpp/calculator_types.cpp
)
# 生成静态库目标
add_library(calculatorgencpp STATIC ${calculatorgencpp_SOURCES})
LINK_AGAINST_THRIFT_LIBRARY(calculatorgencpp thrift)
# 生成calculator_server可执行程序,要求连接test静态库,thrift库
add_executable(calculator_server Calculator_server.cpp)
target_link_libraries(calculator_server ${OpenCV_LIBS})
target_link_libraries(calculator_server calculatorgencpp)
LINK_AGAINST_THRIFT_LIBRARY(calculator_server thrift)
if (ZLIB_FOUND)
target_link_libraries(calculator_server ${ZLIB_LIBRARIES})
endif ()
# 生成calculator_client可执行程序,要求连接test静态库,thrift库
add_executable(calculator_client Calculator_client.cpp)
target_link_libraries(calculator_client ${OpenCV_LIBS})
target_link_libraries(calculator_client calculatorgencpp)
LINK_AGAINST_THRIFT_LIBRARY(calculator_client thrift)
if (ZLIB_FOUND)
target_link_libraries(calculator_client ${ZLIB_LIBRARIES})
endif ()
3.6 Makefile
- 如果写了CMakeLists.txt,则进入build文件夹(没有的话就新建一个)执行:(其中…表示上一级目录)
cmake ..
cmake成功后如下
- 或者在vscode里通过Ctrl + Shift + P 来打开命令行,输入cmake然后选择CMake:Configure
- 如果没写cmakelists,也可以自己编写Makefile
APP:= calculator-app
TARGET_DEVICE = $(shell g++ -dumpmachine | cut -f1 -d -)
ifeq ($(TARGET_DEVICE),aarch64)
CFLAGS:= -DPLATFORM_TEGRA
endif
SRCS:= $(wildcard ./thrift/gen-cpp/*.cpp)
OBJS+= $(SRCS:.cpp=.o)
CFLAGS+= -I/usr/local/include/thrift -I./thrift/gen-cpp
LIBS+= -L/usr/local/lib/ -lthrift
CFLAGS+= `pkg-config --cflags $(PKGS)`
LIBS+= `pkg-config --libs $(PKGS)`
all: $(APP)
%.o: %.c $(INCS) Makefile
$(CXX) -c -o $@ $(CFLAGS) -g $<
$(APP): $(OBJS) Makefile
$(CXX) -o $(APP) $(OBJS) $(LIBS)
clean:
rm -rf $(OBJS) $(APP)
3.7 make并run
执行make,然后
make
结果如下
然后打开两个terminal分别执行
./calculator_server
./calculator_client
结果如下:
其他语言的client类似。只需重新用thrift编译成对应语言源码,再写client。
(完结)