====== 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