天天看點

python 服務端與c++用戶端通訊_thrift初識-c++服務端和python用戶端

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有張經典的介紹圖如下:

python 服務端與c++用戶端通訊_thrift初識-c++服務端和python用戶端

圖中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

#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 ;

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 handler(new echoHandler());

shared_ptr processor(new echoProcessor(handler));

shared_ptr serverTransport(new TServerSocket(port));

shared_ptr transportFactory(new TBufferedTransportFactory());

shared_ptr 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的代碼了。