thrift初識 c++服務端和python客戶端 thrift作為一個跨語言的服務部署框架,目前的應用非常廣泛。 這裡通過thrift實現一個簡單的echo服務來加深對其的理解和印象。入門學習thrift強烈推薦官方文檔 "thrift study" 整個echo服務分為兩個很簡單的部分,服務端和 ...
thrift初識-c++服務端和python客戶端
thrift作為一個跨語言的服務部署框架,目前的應用非常廣泛。
這裡通過thrift實現一個簡單的echo服務來加深對其的理解和印象。入門學習thrift強烈推薦官方文檔thrift study
整個echo服務分為兩個很簡單的部分,服務端和客戶端,thrift是跨語言的,所以我嘗試了兩種不同的語言,用C++做伺服器端,python寫客戶端(畢竟簡單),在實踐之前先介紹下thrift的原理。
thrift工作原理
這裡只做下簡單介紹,因為我也是初學,網上還是有很多其他的好的博文的。
thrift通過它自定義的一種IDL來定義它RPC的規範(介面和數據類型),然後通過編譯器生成不同語言的代碼(gen-cpp,gen-java,gen-py等),底層網路傳輸,協議層的功能都由這些生成的代碼來維護。
thrift的network stack有張經典的介紹圖如下:
- 圖中transport層做為傳輸,其實是一種網路數據讀寫的抽象層,把傳輸和其他系統解耦。
- protocol層,定義transport層的傳輸的數據格式,作序列化和反序列化的格式要求。
- processor層:A Processor encapsulates the ability to read data from input streams and write to output streams. The input and output streams are represented by Protocol objects.
- server層做一個上述功能特性的聚合。
開發人員一般都在server層寫,不過因為業務不同會對不同層次提供的介面採取不同的使用,比如非阻塞的網路IO。
C++服務端
接下來是實踐,寫了一個簡單的echo服務為例。首先在echo.thrift中定義service如下:
service echo{
string echo(1:string msg)
}
然後使用命令thrift -gen cpp echo.thrift和thrift -gen py echo.thrift分別生成c++和python版本的代碼,python的用來做客戶端。
然後修改生成的cpp目錄gen-cpp之下的echo_server.skeleton.cpp,內容如下:
// This autogenerated skeleton file illustrates how to build a server.
// You should copy it to another filename to avoid overwriting it.
#include "echo.h"
#include <protocol/TBinaryProtocol.h>
#include <server/TSimpleServer.h>
#include <transport/TServerSocket.h>
#include <transport/TBufferTransports.h>
#include <iostream>
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 ;
class echoHandler : virtual public echoIf {
public:
echoHandler() {
// Your initialization goes here
}
void echo(std::string& _return, const std::string& msg) {
// Your implementation goes here
// printf("echo\n");
std::cout << "get msg: " << msg << std::endl; //主要就是這個函數的修改
_return = msg;
}
};
int main(int argc, char **argv) {
int port = 9090;
shared_ptr<echoHandler> handler(new echoHandler());
shared_ptr<TProcessor> processor(new echoProcessor(handler));
shared_ptr<TServerTransport> serverTransport(new TServerSocket(port));
shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());
shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory);
server.serve();
return 0;
}
之後編譯,新手編譯可能會遇到兩個問題。第一個問題是找不到thrift,g++提示錯誤Thrift.h: No such file or directory,解決方法也簡單,既然是找不到,那就把它添進去,加上g++編譯選項 -I /usr/local/include/thrift -L /usr/local/lib,添加thrift的安裝路徑的頭文件庫和lib庫。 第二個問題是提示error: ‘uint8_t’ does not name a type,解決辦法也是加上編譯選項-g -DHAVE_NETINET_IN_H,原因參考error:‘uint8_t’ does not name a type. 所以最後編譯命令就是 g++ -g -DHAVE_NETINET_IN_H -I /usr/include/thrift -o server *.cpp -lthrift(lib看情況加不加),這樣就生成的可執行文件server,server預設監聽9090埠。
python客戶端
python客戶端比較簡單,在gen-py目錄中添加client.py文件,內容如下:
#!/usr/bin/env python
#coding:utf-8
import sys
sys.path.append('./')
from echo import echo #引入客戶端類
from thrift import Thrift
from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol
try:
#建立socket
transport = TSocket.TSocket('localhost', 9090)
#選擇傳輸層,這塊要和服務端的設置一致
transport = TTransport.TBufferedTransport(transport)
#選擇傳輸協議,這個也要和服務端保持一致,否則無法通信
protocol = TBinaryProtocol.TBinaryProtocol(transport)
#創建客戶端
client = echo.Client(protocol)
transport.open()
while 1:
msg = raw_input("input msg: ")
msg_ret = client.echo(msg)
print "echo: "+msg_ret
# print "server - " + msg
#關閉傳輸
transport.close()
#捕獲異常
except Thrift.TException, ex:
print "%s" % (ex.message)
最後運行先運行server,之後執行python client.py能得到這樣的結果,在server會收到信息,客戶端輸入的信息也得到回顯。
客戶端
input msg: show parameter
echo: show parameter
input msg:
服務端
get msg: show parameter
最後的內容大致如上所示,以後會慢慢寫更加複雜的thrift的代碼了。