Thrift 的使用


发布于

|

分类

疯狂Get新技能ing

安装Thrift

  • 一般情况下,需要用apt来安装
  • Conda安装的话只有Python相关的模块,C++用不了

写一个thrift文件

比如,叫做 hello.thrift

service DemoService{
    i32 add(1: i32 a, 2: i32 b),
    string say(1: string data),
    string ping()
}

这个例子只有服务。除此之外,还可以有数据结构定义。

生成对应的接口

Python

thrift --gen py hello.thrift

会生成 gen-py 文件夹,将里面的东西作为一个包拿出来用,或者是在代码里面将这个路径加入path

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

C++(CMakefiles文件要自己写啊~我不会)

thrift --gen cpp hello.thrift

如果有其他什么免写CMakefiles文件的方法……请告诉我!

使用

Python

客户端

import sys
import glob

from thrift import Thrift
from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol

from thrift_py.hello import DemoService

def main():
    # Make socket
    transport = TSocket.TSocket('localhost', 4134)

    # Buffering is critical. Raw sockets are very slow
    transport = TTransport.TBufferedTransport(transport)

    # Wrap in a protocol
    protocol = TBinaryProtocol.TBinaryProtocol(transport)

    # Create a client to use the protocol encoder
    client = DemoService.Client(protocol)

    transport.open()

    print(client.ping())
    print('1+100=%d' % client.add(1, 100))
    
    transport.close()


if __name__ == '__main__':
    try:
        main()
    except Thrift.TException as tx:
        print('%s' % tx.message)

服务端有自动生成的代码,可以直接改改用,将里面几个业务函数(add/ping/say)补完整即可

C++

服务端,自动生成的代码没什么坑,只是不知道该怎么把声明和实现分开。

#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/server/TSimpleServer.h>
#include <thrift/transport/TBufferTransports.h>
#include <thrift/transport/TServerSocket.h>
#include <iostream>
#include "thrift/DemoService.h"

using namespace ::apache::thrift;
using namespace ::apache::thrift::protocol;
using namespace ::apache::thrift::transport;
using namespace ::apache::thrift::server;

using boost::shared_ptr;

class DemoServiceHandler : virtual public DemoServiceIf {
 public:
  DemoServiceHandler() = default;

  int32_t add(const int32_t a, const int32_t b) {
    // Your implementation goes here
    std::cout << "Add: " << a << "+" << b << std::endl;
    return a + b;
  }

  void say(std::string &_return, const std::string &data) {
    // Your implementation goes here
    std::cout << "Say: " << data << std::endl;
    _return = "You said:" + data;
  }

  void ping(std::string &_return) {
    // Your implementation goes here
    std::cout << "Ping" << std::endl;
    _return = "Pong";
  }
};

int main(int argc, char **argv) {
  int port = 4134;
  shared_ptr<DemoServiceHandler> handler(new DemoServiceHandler());
  shared_ptr<TProcessor> processor(new DemoServiceProcessor(handler));
  shared_ptr<TServerTransport> serverTransport(new TServerSocket(port));
  shared_ptr<TTransportFactory> transportFactory(
      new TBufferedTransportFactory());
  shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());

  TSimpleServer server(processor, serverTransport, transportFactory,
                       protocolFactory);
  std::cout << "Start server at port " << port << std::endl;
  server.serve();
  std::cout << "Done." << std::endl;

  return 0;
}

客户端,也直接用官方Demo吧:

#include <iostream>

#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/transport/TSocket.h>
#include <thrift/transport/TTransportUtils.h>

#include "thrift/DemoService.h"

using namespace apache::thrift;
using namespace apache::thrift::protocol;
using namespace apache::thrift::transport;

int main() {
  std::cout << "I'm Client" << std::endl;
  std::shared_ptr<TTransport> socket(new TSocket("localhost", 4134));
  std::shared_ptr<TTransport> transport(new TBufferedTransport(socket));
  std::shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));
  DemoServiceClient client(protocol);

  try {
    transport->open();

    std::string send = "Lalala";
    std::string received = "";

    std::cout << "ping()" << std::endl;
    client.ping(received);
    std::cout << received << std::endl;

    std::cout << "1 + 1 = " << client.add(1, 1) << std::endl;

    client.say(received, send);
    std::cout << received << std::endl;

    transport->close();
  } catch (TException& tx) {
    std::cout << "ERROR: " << tx.what() << std::endl;
  }

  return 0;
}

另外就是要注意一下参数的顺序和要求……比如,thrift里返回为string的,在客户端这里都是string&,需要先定义一个string再传进去,并且好像一般返回值是第一个参数。这一点比较不适应。

使用建议

用C++写服务端(运行速度比较快) 用Python写客户端(开发速度比较快)

为啥这样说呢?——gen之后,默认生成的代码里面,cpp给的是服务端代码,python给的是客户端代码。——人家都替你想好啦~

使用建议2

Python的话,有个东西叫 ThriftPy2,可以直接加载thrift idl文件,而不用首先生成Python代码,而且可以一键生成Client,甚是方便。


评论

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注