一、簡介
thrift來自於facebook,是一個軟件框架,用來進行可擴展且跨語言的服務的開發。允許你定義一個簡單的定義文件中的數據類型和服務接口。以作爲輸入文件,編譯器生成代碼用來方便地生成RPC客戶端和服務器通信的無縫跨編程語言。它可支持 C++、 Java,、Python,、PHP、C#等等一些主流的語言,類似於Google的protobuf,關於兩者之間的比較網上也有很多,還有一個後起之秀avro有hadoop的背景,也值得關注。由於我最早接觸的是thrift,因此一直都在使用這個,而且已在幾個項目中使用了,沒出現過什麼問題,因此也沒心思去研究protobuf和avro了。
二、下載與安裝
環境:Ubuntu
依賴:boost、libevent
下載地址:http://thrift.apache.org/download/
下載文件:thrift-0.9.0.tar.gz
我用的是Ubuntu,按照官網給出的安裝步驟安裝沒什麼問題,主要是要依賴boost和libevent,把這兩個裝好就可以。可直接使用官網給的命令:
sudo apt-get install libboost-dev libboost-test-dev libboost-program-options-dev libevent-dev automake libtool flex bison pkg-config g++ libssl-dev
由於我常用boost開發,已經安裝過了boost,因此直接連接過去就可以。
$>tar xvf thrift-0.9.0.tar.gz
$>ch thrift-0.9.0
$>./config --prefix=/usr/local/thrift --with-boost=/usr/local/boost
$>make
$>make install
三、測試
直接使用官網的例子
1.編寫代碼生成腳本文件
UserStorage.thrift(注:後綴必須是thrift,文件名會生成類名)
struct UserProfile {
1: i32 uid,
2: string name,
3: string blurb
}
service UserStorage {
void store(1: UserProfile user),
UserProfile retrieve(1: i32 uid)
}
要將$THRIFT_HOME/bin加入環境變量的PATH中,然後執行命令:
$>thrift -gen cpp UserStorage.thrift
這是當前目錄下會有個gen-cpp的目錄,裏面包含了生成的相關C++代碼(也可以通過thrift命令生成其它代碼,如:thrift -gen java UserStorage.thrift ,這樣就生成了java代碼):
UserStorage.h
UserStorage.cpp
UserStorage_types.h
UserStorage_types.cpp
UserStorage_constants.h
UserStorage_constants.cpp
UserStorage_server.skeleton.cpp
上面標紅的文件是我們這個例子所需的代碼,另外三個可暫時不用管。
2.編寫服務器端代碼
server.cpp
#include <iostream>
#include <boost/shared_ptr.hpp>
#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/transport/TBufferTransports.h>
#include <thrift/transport/TServerSocket.h>
#include <thrift/server/TSimpleServer.h>
#include "UserStorage.h"
using namespace apache::thrift;
using namespace apache::thrift::protocol;
using namespace apache::thrift::transport;
using namespace apache::thrift::server;
using namespace apache::thrift::concurrency;
using namespace boost;
class UserStorageHandler : virtual public UserStorageIf {
public:
UserStorageHandler() {
// Your initialization goes here
}
void store(const UserProfile& user) {
// Your implementation goes here
printf("store\n");
}
void retrieve(UserProfile& _return, const int32_t uid) {
// Your implementation goes here
printf("retrieve\n");
}
};
int main(int argc, char **argv) {
int port = 9090;
shared_ptr handler(new UserStorageHandler());
shared_ptr processor(new UserStorageProcessor(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;
}
g++ -o server -I/usr/local/boost/include -I/usr/local/thrift/include -L/usr/local/boost/lib -L/usr/local/thrift/lib -lthrift -lthriftnb -levent server.cpp
3.客戶端代碼
client.cpp
#include <iostream>
#include <boost/shared_ptr.hpp>
#include <thrift/transport/TSocket.h>
#include <thrift/transport/TBufferTransports.h>
#include <thrift/protocol/TProtocol.h>
#include <thrift/protocol/TBinaryProtocol.h>
#include "UserStorage.h"
using namespace apache::thrift;
using namespace apache::thrift::transport;
using namespace apache::thrift::protocol;
using namespace boost;
int main()
{
boost::shared_ptr<TTransport> m_sock;
boost::shared_ptr<TTransport> m_pTransport;
boost::shared_ptr<TProtocol> m_protocol;
shared_ptr<UserStorageClient> m_pClient;
m_sock.reset(new TSocket("127.0.0.1", 9090));
m_pTransport.reset(new TFramedTransport(m_sock));
m_protocol.reset(new TBinaryProtocol(m_pTransport));
m_pClient.reset(new UserStorageClient(m_protocol));
m_pTransport->open();
UserProfile up;
up.uid = 1;
up.name = "bocheng";
up.blurb = "1";
m_pClient->store(up);
return 0;
}
g++ -o client -I/usr/local/boost/include -I/usr/local/thrift/include -L/usr/local/boost/lib
-L/usr/local/thrift/lib -lthrift -lthriftnb -levent client.cpp
這只是一個比較簡單的例子,服務器是用的是TSimpleServer,是阻塞單線程的服務器,一般在線上跑的不會用到這個服務器,因此後續篇會介紹如何使用TNonblockingServer編寫非阻塞多線程的服務器。