====== Thrift Tutorial ======
===== - Abstract =====
本Demo用于展示 Thrift 跨平台(Linux,Windows)、跨编程语言(Python,Javascript,C++)的远过程调用(传输消息)功能,实现从某一应用程序(client)向另一应用程序(server)发送消息的过程。
* Server端(被调用的过程)实现两个接口:
ping() -- 原文返回Client端送来的文本,在前面添加文本"echo:"
post() -- 接收client送来的一个JSON字符串,并添加 "res":True 字段/数值作为回应,否则,当收到非法JSON串,返回包含 "res":False 字段/数值 的JSON串。
* Client端调用 ping 和 post接口,并打印返回值。
已完成测试:
Windows : Python, Javascript
Linux: Python, C++
^ ^ Windows |^ Linux ||
| ::: ^ Server ^ Client ^ Server ^ Client ^
^ Python | √ | √ | √ | √ |
^ JScript | | | | √ |
^ C++ | | | | √ |
==== - Install Thrift on Window ====
* Get the latest Thrift from [[https://thrift.apache.org/download]]
* Get the exe file thrift-x.xx.x.exe, change the filename to thrift.exe
==== - Install Thrift on Ubuntu ====
* 安装相关依赖包
sudo apt-get install automake bison flex g++ git libboost-all-dev libevent-dev libssl-dev libtool make pkg-config
* 下载 Thrift 并解压(可采取多种下载方式)
wget https://dlcdn.apache.org/thrift/0.15.0/thrift-0.15.0.tar.gz
tar -xf thrift-0.15.0.tar.gz
* 配置
./configure
配置运行结果:
thrift 0.16.0
Building C (GLib) Library .... : no
Building C++ Library ......... : yes
Building Common Lisp Library.. : no
Building D Library ........... : no
Building Dart Library ........ : no
Building .NET Standard Library : no
Building Erlang Library ...... : no
Building Go Library .......... : no
Building Haxe Library ........ : no
Building Java Library ........ : no
Building Lua Library ......... : no
Building NodeJS Library ...... : no
Building Perl Library ........ : no
Building PHP Library ......... : no
Building Python Library ...... : yes
Building Py3 Library ......... : yes
Building Ruby Library ........ : no
Building Rust Library ........ : no
Building Swift Library ....... : no
C++ Library:
C++ compiler .............. : g++ -std=c++11
Build TZlibTransport ...... : yes
Build TNonblockingServer .. : yes
Build TQTcpServer (Qt5) ... : no
C++ compiler version ...... : g++ (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0
Python Library:
Using Python .............. : /usr/bin/python
Using Python version ...... : Python 3.8.10
Using Python3 ............. : /usr/bin/python
Using Python3 version ..... : Python 3.8.10
If something is missing that you think should be present,
please skim the output of configure to find the missing
component. Details are present in config.log.
确认支持 C++, Python
* 编译、安装、验证安装成功
sudo make
sudo make install
thrift -version
显示以下信息表示安装成功:
Thrift version 0.16.0
* 更新系统环境
修改/etc/ld.so.conf文件,增加搜索路径,将/usr/local/lib添加到ld.so.conf文件中(指定库文件 *.so 的路径,否则运行应用程序时会出现缺少库文件错误)
sudo ldconfig
==== - Thrift supported data type ====
基本数据类型
数据类型简单明了,包含了所有编程语言中的可用基本数据类型。
bool:布尔值(true/false)
byte:8位有符号整型
i16:16位有符号整型
i32:32位有符号整型
i64:64位有符号整型
double:64位浮点数
string:由utf8编码的文本字符串
特殊类型
binary:未编码的字节流
结构体(struct)
容器(container)
枚举
服务
命名空间
注释
===== - Service description file =====
A RPC description file below defining the RPC service interfaces.
service DemoService
{
string ping(1:string param)
string post(1:string param)
}
===== - @Python =====
==== - Install Thrift module ====
pip install thrift
==== - Generate interface ====
# Interface for Python,generated code at ./gen-py
thrift --gen py DemoService.thrift
==== - Service and Client code ====
from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol
from thrift.server import TServer
import sys
sys.path.append("./gen-py/")
from DemoService import DemoService
import json
class DemoServer:
def __init__(self):
self.log = {}
def ping(self, param):
return "echo:" + param
def post(self, jstr):
try:
jdict = json.loads(jstr)
except Exception as e :
return json.dumps({"res":False})
jdict["res"] = True
return json.dumps(jdict);
if __name__ == '__main__':
handler = DemoServer()
processor = DemoService.Processor(handler)
# 监听端口
transport = TSocket.TServerSocket(host="0.0.0.0", port=9999)
# 选择传输层
tfactory = TTransport.TBufferedTransportFactory()
# 选择传输协议
pfactory = TBinaryProtocol.TBinaryProtocolFactory()
# 创建服务端
server = TServer.TThreadPoolServer(processor, transport, tfactory, pfactory)
# 设置连接线程池数量
server.setNumThreads(5)
# 启动服务
server.serve()
from thrift import Thrift
from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol
import sys
sys.path.append("./gen-py/")
from DemoService import DemoService
import json
if __name__ == '__main__':
transport = TSocket.TSocket('127.0.0.1', 9999)
transport = TTransport.TBufferedTransport(transport)
protocol = TBinaryProtocol.TBinaryProtocol(transport)
client = DemoService.Client(protocol)
# 连接服务端
transport.open()
recv = client.ping("test")
print(recv)
recv = client.post(json.dumps({"Request":"Play"}) )
print(recv)
# 断连服务端
transport.close()
==== - Test ====
运行服务端:
# Run service
python service.py
运行Client端:
# Run client
python client.py
运行结果:
echo:test
{"Request": "Play", "res": true}
===== - @ Node.js =====
==== - Install Thrift module ====
npm install thrift
==== - Generate interface ====
# Interface for Node.js, generated code at ./gen-node.js
thrift --gen js:node DemoService.thrift
==== - Client code ====
var thrift = require('thrift');
var DemoService = require('./gen-nodejs/DemoService.js');
var transport = thrift.TBufferdTransport;
var protocol = thrift.TBinaryProtocol;
var connection = thrift.createConnection('localhost', 9999,{
transport : transport,
protocol : protocol
});
client = thrift.createClient(DemoService, connection);
connection.on('error', function(err) {
console.error(err);
});
client.ping('From Node.js')
.then(log);
var json = {
"Source": "node.js",
"Request": "None"
}
client.post( JSON.stringify(json))
.then(log)
function log(msg) {
console.log(msg);
}
==== - Test ====
运行client:
node client.js
运行结果:
echo:From Node.js
{"Source": "node.js", "Request": "None", "res": true}
===== - @C++ =====
==== - Generate interface ====
# Interface for C++,generated code at ./gen-cpp
thrift -r --gen cpp DemoService.thrift
==== - Client code ====
#include
#include "gen-cpp/DemoService.h"
#include
#include
#include
using namespace apache::thrift;
using namespace apache::thrift::protocol;
using namespace apache::thrift::transport;
using namespace std;
#define REMOTE_ADDRESS "192.168.109.1"
#define REMOTE_PORT 9999
int main(int argc, char **argv) {
string res;
::std::shared_ptr socket(new TSocket(REMOTE_ADDRESS, REMOTE_PORT));
::std::shared_ptr transport(new TBufferedTransport(socket));
::std::shared_ptr protocol(new TBinaryProtocol(transport));
DemoServiceClient client(protocol);
transport->open();
client.ping(res, "From C++ Client");
cout << res << '\n';
client.post(res, "{\"Source\":\"C++\"}");
cout << res << '\n';
transport->close();
return 0;
}
// g++ -g -I/usr/local/include/thrift gen-cpp/DemoService.cpp client.cpp -lthrift -L/usr/local/lib/*.so -o client
编译:
g++ -g -I/usr/local/include/thrift gen-cpp/DemoService.cpp client.cpp -lthrift -L/usr/local/lib/*.so -o client
运行client:
./client
运行结果:
echo:From C++ Client
{"Source": "C++", "res": true}
==== - Service code ====
#include
#include "gen-cpp/DemoService.h"
#include
#include
#include
#include
using namespace apache::thrift;
using namespace apache::thrift::protocol;
using namespace apache::thrift::transport;
using namespace apache::thrift::server;
using boost::shared_ptr;
using namespace std;
#define REMOTE_ADDRESS "192.168.109.1"
#define REMOTE_PORT 9999
class ServiceHandler : virtual public ServiceIf {
public:
ServiceHandler() {
}
void ping(std::string& _return, const std::string& param) {
cout << param << '\n';
}
void post(std::string& _return, const std::string& param) {
cout << param << '\n';
}
};
int main(int argc, char **argv) {
int port = 9090;
stdcxx::shared_ptr handler(new ServiceHandler());
stdcxx::shared_ptr processor(new ServiceProcessor(handler));
stdcxx::shared_ptr protocolFactory(new TBinaryProtocolFactory());
stdcxx::shared_ptr serverTransport(new TNonblockingServerSocket(port));
stdcxx::shared_ptr threadFactory = std::shared_ptr(new PlatformThreadFactory());
stdcxx::shared_ptr threadManager = ThreadManager::newSimpleThreadManager(10);
threadManager->threadFactory(threadFactory);
threadManager->start();
stdcxx::shared_ptr server(new TNonblockingServer(processor, protocolFactory, serverTransport, threadManager));
server->serve();
return 0;
}
// g++ -g -I/usr/local/include/thrift gen-cpp/DemoService.cpp service.cpp -lthrift -L/usr/local/lib/*.so -o service