天天看点

使用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