天天看點

使用thrift做c++,java和python的互相調用

linux上安裝thrift見

<a href="http://jinghong.iteye.com/blog/1102535">http://jinghong.iteye.com/blog/1102535</a>

thrift做為跨語言調用的方案有高效,支援語言較多,成熟等優點;代碼侵入較強是其弱點。

下面記錄以C++做伺服器,C++,java和python做用戶端的示例,這個和本人現在工作環境吻合,使用多線程長連接配接的socket來建立高效分布式系統的跨語言調用平台。

遺憾的是目前版本(0.7.0)的C語言還不支援Compact協定,導緻在現在的環境中nginx c module調用thrift要使用binary協定。thrift開發團隊似乎對C語言不太感冒。

1.定義idl檔案acsuser.thrift

Idl代碼

struct User{   

 1: string uid,   

 2: string uname,   

 3: bool usex,   

 4: i16 uage,   

}   

service UserService{   

 void add(1: User u),   

 User get(1: string uid),   

}  

2.生成c++,java和python代碼架構

Shell代碼

thrift -r --gen cpp acsuser.thrift    

thrift -r --gen java acsuser.thrift    

thrift -r --gen py acsuser.thrift   

這時生成子目錄gen-cpp,gen-java,gen-py

3.生成C++服務端代碼

cp gen-cpp/UserService_server.skeleton.cpp UserServer.cpp  

修改UserServer.cpp

C++代碼

#include "UserService.h"

#include &lt;config.h&gt;

//#include &lt;protocol/TBinaryProtocol.h&gt;

#include &lt;protocol/TCompactProtocol.h&gt;

#include &lt;server/TSimpleServer.h&gt;

#include &lt;transport/TServerSocket.h&gt;

#include &lt;transport/TBufferTransports.h&gt;

#include &lt;concurrency/ThreadManager.h&gt;

#include &lt;concurrency/PosixThreadFactory.h&gt;

#include &lt;server/TThreadPoolServer.h&gt;

#include &lt;server/TThreadedServer.h&gt;

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 boost::shared_ptr;   

class UserServiceHandler : virtual public UserServiceIf {

 public:   

  UserServiceHandler() {   

    // Your initialization goes here

  }   

  void add(const User&amp; u) {   

    // Your implementation goes here

    printf("uid=%s uname=%s usex=%d uage=%d\n", u.uid.c_str(), u.uname.c_str(), u.usex, u.uage);   

  void get(User&amp; _return, const std::string&amp; uid) {   

    _return.uid = "leo1";   

    _return.uname = "yueyue";   

    _return.usex = 1;   

    _return.uage = 3;   

    printf("uid=%s uname=%s usex=%d uage=%d\n", _return.uid.c_str(), _return.uname.c_str(), _return.usex, _return.uage);   

};   

int main(int argc, char **argv) {

  shared_ptr&lt;UserServiceHandler&gt; handler(new UserServiceHandler());   

  shared_ptr&lt;TProcessor&gt; processor(new UserServiceProcessor(handler));   

  shared_ptr&lt;TProtocolFactory&gt; protocolFactory(new TCompactProtocolFactory());   

  shared_ptr&lt;TTransportFactory&gt; transportFactory(new TBufferedTransportFactory());   

  shared_ptr&lt;TServerTransport&gt; serverTransport(new TServerSocket(9090));   

  shared_ptr&lt;ThreadManager&gt; threadManager = ThreadManager::newSimpleThreadManager(10);   

  shared_ptr&lt;PosixThreadFactory&gt; threadFactory = shared_ptr&lt;PosixThreadFactory&gt;(new PosixThreadFactory());   

  threadManager-&gt;threadFactory(threadFactory);   

  threadManager-&gt;start();   

  printf("start user server...\n");   

  TThreadPoolServer server(processor, serverTransport, transportFactory, protocolFactory, threadManager);   

  server.serve();   

  return 0;   

注意這段代碼使用TCompactProtocol,需要#include &lt;config.h&gt;

另外這個是Blocking的多線程伺服器

4.生成C++的client檔案UserClient.cpp

#include &lt;transport/TSocket.h&gt;

using namespace apache::thrift;   

using namespace apache::thrift::protocol;   

using namespace apache::thrift::transport;   

        boost::shared_ptr&lt;TSocket&gt; socket(new TSocket("localhost", 9090));   

        boost::shared_ptr&lt;TTransport&gt; transport(new TBufferedTransport(socket));   

        boost::shared_ptr&lt;TProtocol&gt; protocol(new TCompactProtocol(transport));   

        transport-&gt;open();   

        User u;   

        u.uid = "leo";   

        u.uname = "yueyue";   

        u.usex = 1;   

        u.uage = 3;   

        UserServiceClient client(protocol);   

        client.add(u);   

        User u1;   

        client.get(u1,"lll");   

        transport-&gt;close();   

        printf("uid=%s uname=%s usex=%d uage=%d\n", u1.uid.c_str(), u1.uname.c_str(), u1.usex, u1.uage);   

        return 0;   

5.生成Makefile

Makefile代碼

BOOST_DIR = /usr/local/include/boost/   

THRIFT_DIR = /usr/local/include/thrift   

LIB_DIR = /usr/local/lib   

GEN_SRC = ./gen-cpp/acsuser_types.cpp ./gen-cpp/acsuser_constants.cpp ./gen-cpp/UserService.cpp   

default: server client   

server: UserServer.cpp   

        g++ -g -o UserServer -I${THRIFT_DIR} -I${BOOST_DIR}  -I./gen-cpp -L${LIB_DIR} -lthrift UserServer.cpp ${GEN_SRC}   

client: UserClient.cpp   

        g++ -g -o UserClient -lm -pthread -lz -lrt -lssl -I${THRIFT_DIR} -I${BOOST_DIR}  -I./gen-cpp -L${LIB_DIR} -lthrift UserClient.cpp ${GEN_SRC}   

clean:   

        $(RM) -r UserServer UserClient  

6.啟動c++ server

./UserServer  

7.測試c++ client

./UserClient  

8.寫java client檔案UserClient.java

Java代碼

import org.apache.thrift.TException;   

import org.apache.thrift.protocol.TCompactProtocol;   

import org.apache.thrift.protocol.TProtocol;   

import org.apache.thrift.transport.TFramedTransport;   

import org.apache.thrift.transport.TNonblockingSocket;   

import org.apache.thrift.transport.TSocket;   

import org.apache.thrift.transport.TTransport;   

import org.apache.thrift.transport.TTransportException;   

//import UserService.Client;

public class UserClient {   

    private void start() {   

        try {   

            TTransport socket = new TSocket("localhost", 9090);

            //TTransport transport = new TFramedTransport(socket);

            TProtocol protocol = new TCompactProtocol(socket);   

            UserService.Client client = new UserService.Client(protocol);   

            socket.open();   

            System.out.println(client.get("lll"));   

            User u = new User();   

            u.uid="leojava";   

            u.uname="yueyue";   

            u.usex=true;   

            u.uage=3;   

            client.add(u);   

            socket.close();   

        } catch (TTransportException e) {   

            e.printStackTrace();   

        } catch (TException e) {   

        }   

    }   

    public static void main(String[] args) {

        UserClient c = new UserClient();   

        c.start();   

編譯和運作java client

javac -classpath /usr/local/lib/libthrift-0.7.0.jar:/usr/local/lib/log4j-1.2.14.jar:/usr/local/lib/commons-logging-1.1.1.jar:/usr/local/lib/slf4j-api-1.5.8.jar UserClient.java ./gen-java/*.java

java -classpath .:./gen-java:/usr/local/lib/libthrift-0.7.0.jar:/usr/local/lib/log4j-1.2.14.jar:/usr/local/lib/commons-logging-1.1.1.jar:/usr/local/lib/slf4j-api-1.5.8.jar:/usr/local/lib/slf4j-log4j12-1.5.8.jar UserClient  

9.寫Python client檔案PythonClient.py

Python代碼

#!/usr/bin/env python

import sys   

sys.path.append('./gen-py')   

from acsuser import UserService   

from acsuser.ttypes import *   

from thrift import Thrift   

from thrift.transport import TSocket   

from thrift.transport import TTransport   

from thrift.protocol import TCompactProtocol   

# Make socket

transport = TSocket.TSocket('localhost', 9090)   

# Buffering is critical. Raw sockets are very slow

transport = TTransport.TBufferedTransport(transport)   

# Wrap in a protocol

protocol = TCompactProtocol.TCompactProtocol(transport)   

# Create a client to use the protocol encoder

client = UserService.Client(protocol)   

# Connect!

transport.open()   

# Call Server services  

u = client.get('lll')   

print 'uid=%s uname=%s usex=%d u.uage=%d' %(u.uid,u.uname,u.usex,u.uage)   

u1 = User()   

u1.uid='leo'  

u1.uname='yueyue'  

u1.usex=1  

u1.uage=3  

client.add(u1)  

執行python client代碼

chmod 777 PythonClient.py   

./PythonClient.py