2016年4月22日 星期五

Thrift C++ on Linux with Makefile Tutorial


首先假设你已经安装好thrift,我用的是CentOS7.2

C++

[root@thrift gen-cpp]# thrift --version
Thrift version 1.0.0-dev

准备thrift档案内容如下
[root@thrift cal]# vi cal.thrift
struct nums {
    1: i32 i1;
    2: i32 i2;
}

service sumservice {
    void sum(1: nums n)
}

然后用thrift产生cpp的header及source档案
[root@thrift cal]# thrift --gen cpp cal.thrift

可以看见产生了gen-cpp文件夹,进入gen-cpp文件夹,看见以下几个产生出来的文件。
其中3组.h及.cpp文件:cal_constants.*,cal_types.*,sumservice.*,共6个文件thrift已经完全写好。
cal_constants.* 及 cal_types.* 的命名方式是基于cal.thrift档案名称的
sumservice.* 的命名方式cal.thrift档案里面所有的service的名称的
sumservice.*是server side交易资料的implementation
产生出来的3组.h及.cpp合共全部6个文件一般无需自行更改
[root@thrift sum]# ls && cd gen-cpp/ && ls
cal.thrift  gen-cpp
cal_constants.cpp  cal_types.cpp  sumservice.cpp  sumservice_server.skeleton.cpp
cal_constants.h    cal_types.h    sumservice.h

留意sumservice.*里面的几个class名字及顺序
If, IfFactory, IfSingletonFactory, Null:If
args__isset, args, pargs, result, presult
Client:If, Processor:TDispatchProcessor, ProcessorFactory:TPorcessorFactory
Multiface:If, ConcurrentClient : If, 

唯一需要自行更改的是sumservice_server.skeleton.cpp, 这是Handler:If的
原本这个sumservice的预设implementation是把function名字打印出来
[root@thrift gen-cpp]# vi sumservice_server.skeleton.cpp
class sumserviceHandler : virtual public sumserviceIf {
 public:
  sumserviceHandler() {
    // Your initialization goes here
  }
  void sum(const nums& n) {
    // Your implementation goes here
    printf("sum\n");
  }
};
其中的main function大意是这样的,主要有关联的是Handler>TProcessor>TSimpleServer,而ServerTransport, TransportFactory及ProtocolFactory是配角。
int main() {
  TSimpleServer server(TProcessor(sumserviceHandler()));
  server.server();
};

由于每次运行都会把这歌现有的skeleton覆盖掉,所以现在干脆直接改名以免后顾之忧,改名以后列出的档案也比较工整
[root@thrift gen-cpp]# mv sumservice_server.skeleton.cpp server.cpp && ls
cal_constants.cpp  cal_types.cpp  client.cpp  sumservice.cpp
cal_constants.h    cal_types.h    server.cpp  sumservice.h

我们把server.cpp其中的两个方法改成以下有意义的内容,值得注意的是这两个方法都是放在一个由sumserviceIf界面虚疑继承的
[root@thrift gen-cpp]# vi server.cpp
class sumserviceHandler : virtual public sumserviceIf {
sumserviceHandler() {
    printf("server created \n");
  }
void sum(const nums& n) {
    printf("sum: %d + %d = %d \n", n.i1, n.i2, n.i1 + n.i2);
  }
}

用g++编译server程序 其中server档案需要参考types, constants 及service档案,留意最后要加上-lthrift
[root@thrift gen-cpp]# g++ -o server server.cpp sumservice.cpp cal_types.cpp cal_constants.cpp -lthrift

可以试试把server程序跑起来,并且看见sumserviceHandler的建构子被呼叫了
[root@thrift gen-cpp]# ls
cal_constants.cpp  cal_types.cpp  server          sumservice.h
cal_constants.h    cal_types.h    sumservice.cpp  server.cpp
[root@thrift gen-cpp]# ./server
server created
^C


下一步要建立client代码去跟server程序沟通
首先要从sumservice.h找出你等下准备要继承的client class, grep Client一下会发现名有两个classes sumserviceClient  sumserviceConcurrentClient 
[root@thrift gen-cpp]# grep Client sumservice.h
#include <thrift/async/TConcurrentClientSyncInfo.h>
class sumserviceClient : virtual public sumserviceIf {
  sumserviceClient(boost::shared_ptr< ::apache::thrift::protocol::TProtocol> prot) {
  sumserviceClient(boost::shared_ptr< ::apache::thrift::protocol::TProtocol> iprot, boost::shared_ptr< ::apache::thrift::protocol::TProtocol> oprot) {
class sumserviceConcurrentClient : virtual public sumserviceIf {
  sumserviceConcurrentClient(boost::shared_ptr< ::apache::thrift::protocol::TProtocol> prot) {
  sumserviceConcurrentClient(boost::shared_ptr< ::apache::thrift::protocol::TProtocol> iprot, boost::shared_ptr< ::apache::thrift::protocol::TProtocol> oprot) {
  ::apache::thrift::async::TConcurrentClientSyncInfo sync_;


client跟server的基本代码结构非常类似,所以直接考出来修改
[root@thrift gen-cpp]# cp server.cpp client.cpp && vi client.cpp

顶头加入TSocket.h并把main方法改成以下
#include <thrift/transport/TSocket.h>
int main(int argc, char **argv) {
  shared_ptr<TSocket> socket(new TSocket("localhost", 9090));
  shared_ptr<TTransport> transport(new TBufferedTransport(socket));
  shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));
  transport->open();
  // client code starts here
  nums n;
  n.i1 = 1;
  n.i2 = 2;
  sumserviceClient(protocol).sum(n);
  // client code ends here
  transport->close();
  return 0;
}

client.cpp以下几句只跟server有关却跟client无关,正在写client code的我们为求简洁把他们移除掉。不怕,万一忘记移除,client程序还是可以编译跑起来的。
#include <thrift/server/TSimpleServer.h>
#include <thrift/transport/TServerSocket.h>
using namespace ::apache::thrift::server;
class sumserviceHandler
shared_ptr<sumserviceHandler> handler(new sumserviceHandler());
shared_ptr<TProcessor> processor(new sumserviceProcessor(handler));
shared_ptr<TServerTransport> serverTransport(new TServerSocket(port));

client.cpp中你会看见原本server的TTransportFactory及TProtocolFactory,如果把它们的Factory去掉就会变成client的要员
  1. boost::shared_ptr<TSocket> socket(new TSocket("localhost", 9090));    
  2.     boost::shared_ptr<TTransport> transport(new TBufferedTransport(socket));    
  3.     boost::shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport)); 

client.cpp整个就是这样
#include "sumservice.h"
#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/transport/TBufferTransports.h>
using namespace ::apache::thrift;
using namespace ::apache::thrift::protocol;
using namespace ::apache::thrift::transport;
using boost::shared_ptr;
#include <thrift/transport/TSocket.h>
int main(int argc, char **argv) {
  shared_ptr<TSocket> socket(new TSocket("localhost", 9090));
  shared_ptr<TTransport> transport(new TBufferedTransport(socket));
  shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));
  transport->open();
  // client code starts here
  nums n;
  n.i1 = 1;
  n.i2 = 2;
  sumserviceClient(protocol).sum(n);
  // client code ends here
  transport->close();
  return 0;
}


可以编译了
[root@thrift gen-cpp]# g++ -o client client.cpp sumservice.cpp cal_types.cpp cal_constants.cpp -lthrift

如果看见這个问题不要紧
[ricky@thrift1 gen-cpp]$ ./server
./server: error while loading shared libraries: libthrift-1.0.0-dev.so: cannot open shared object file: No such file or directory

再跑一次就可以
$ LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib
$ export LD_LIBRARY_PATH
$ ./server


可以跑了!背景跑server,前景跑client
[root@thrift gen-cpp]# ./server &
[1] 22189
[root@thrift gen-cpp]# server created
./client
sum: 1 + 2 = 3
[root@thrift gen-cpp]# pkill server


做个最原始的makefile,可以看到server跟client档案的dependency
[root@thrift gen-cpp]# vi makefile

.PHONY: all
all: server client

server: cal_constants.cpp cal_types.cpp sumservice.cpp cal_constants.h cal_types.h server.cpp sumservice.h
        g++ -std=c++11 -o server cal_constants.cpp cal_types.cpp sumservice.cpp server.cpp -lthrift
client: cal_constants.cpp cal_types.cpp client.cpp sumservice.cpp cal_constants.h cal_types.h server.cpp sumservice.h
        g++ -std=c++11 -o client cal_constants.cpp cal_types.cpp sumservice.cpp client.cpp -lthrift


Python

假设你不用C++而要使用Python,用thrift产生cpp的header及source档案
[root@thrift sum]# thrift --gen py cal.thrift && ls && ls ./gen-py/ && ls ./gen-py/cal
cal.thrift  gen-cpp  gen-py
cal  __init__.py
constants.py  __init__.py  sumservice.py  sumservice-remote  ttypes.py


可以看到thrift并不会把server代码skeleton产生给你,于是你需要在thrift档案同一目录下,建立以下的server.py,值得注意的是里面的CalHandler这个类并没有使用继承,只要是任何一个有写好sum(self,n)的类就可以送给sumservice.Processor()去被呼叫。留意,sumservice.py已经由thrift写好里面传送的代码,不用自己修改的。
[root@thrift sum]# vi server.py
#!/usr/bin/env python
import socket
import sys
sys.path.append('./gen-py')
from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol
from thrift.server import TServer
from cal import sumservice
from cal.ttypes import *
class CalHandler :
    def sum(self, n) :
        print(n.i1 + n.i2)
handler = CalHandler()
processor = sumservice.Processor(handler)
transport = TSocket.TServerSocket("127.0.0.1", 9090)
tfactory = TTransport.TBufferedTransportFactory()
pfactory = TBinaryProtocol.TBinaryProtocolFactory()
server = TServer.TSimpleServer(processor, transport, tfactory, pfactory)

server.serve()

参考./gen-py/sum/ttypes.py,可以看见nums已经写好了建构子,与c++的POD struct不同
class nums(object):
    def __init__(self, i1=None, i2=None,):
        self.i1=i1
        self.i2=i2

[root@thrift sum]# vi client.py
#!/usr/bin/env python
import sys
sys.path.append('./gen-py')
from thrift import Thrift
from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol
from cal import sumservice
from cal.ttypes import *
try:
    transport = TSocket.TSocket('127.0.0.1', 9090)
    transport = TTransport.TBufferedTransport(transport)
    protocol = TBinaryProtocol.TBinaryProtocol(transport)
    client = sumservice.Client(protocol)
    transport.open()
    client.sum(nums(1,2)) # call constructor of nums() class from ttypes.py
    transport.close()
except Thrift.TException as ex:

    print ("%s" % (ex.message))

Java

must use "127.0.0.1" instead of "localhost" in server.py and JavaClient.java

JavaClient.java
import org.apache.thrift.TException;
import org.apache.thrift.transport.TSSLTransportFactory;
import org.apache.thrift.transport.TTransport;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TSSLTransportFactory.TSSLTransportParameters;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TProtocol;
public class JavaClient {
    public static void main(String[] args) {
        try {
            TTransport transport;
            transport = new TSocket("127.0.0.1", 9090);
            transport.open();
            TProtocol protocol = new  TBinaryProtocol(transport);
            sumservice.Client client = new sumservice.Client(protocol);
            client.sum(new nums(1, 6));
            System.out.println("done");
            transport.close();
        }
        catch (TException x) {
            x.printStackTrace();
        }
    }
}

[ricky@thrift2 cal]$ thrift --gen java cal.thrift && ls gen-java
nums.java  sumservice.java

[ricky@thrift1 gen-java]$ pwd
/home/ricky/dev/Thrift/cal/gen-java
cp /path/to/thrift/lib/java/build/lib/*.jar ./lib/
cp /path/to/thrift/lib/java/build/libthrift-1.0.0.jar ./lib/

[ricky@thrift2 gen-java]$ javac -cp ".:./lib/*" JavaClient.java && java -cp ".:./lib/*" JavaClient






asdfas

沒有留言:

張貼留言

2023 Promox on Morefine N6000 16GB 512GB

2023 Promox on Morefine N6000 16GB 512GB Software Etcher 100MB (not but can be rufus-4.3.exe 1.4MB) Proxmox VE 7.4 ISO Installer (1st ISO re...