thrift初识-c++服务端和python客户端

thrift初识-c++服务端和python客户端

thrift作为一个跨语言的服务部署框架,目前的应用非常广泛。
这里通过thrift实现一个简单的echo服务来加深对其的理解和印象。入门学习thrift强烈推荐官方文档thrift study

整个echo服务分为两个很简单的部分,服务端和客户端,thrift是跨语言的,所以我尝试了两种不同的语言,用C++做服务器端,python写客户端(毕竟简单),在实践之前先介绍下thrift的原理。

thrift工作原理

这里只做下简单介绍,因为我也是初学,网上还是有很多其他的好的博文的。
thrift通过它自定义的一种IDL来定义它RPC的规范(接口和数据类型),然后通过编译器生成不同语言的代码(gen-cpp,gen-java,gen-py等),底层网络传输,协议层的功能都由这些生成的代码来维护。
thrift的network stack有张经典的介绍图如下:

  1. 图中transport层做为传输,其实是一种网络数据读写的抽象层,把传输和其他系统解耦。
  2. protocol层,定义transport层的传输的数据格式,作序列化和反序列化的格式要求。
  3. processor层:A Processor encapsulates the ability to read data from input streams and write to output streams. The input and output streams are represented by Protocol objects.
  4. server层做一个上述功能特性的聚合。

开发人员一般都在server层写,不过因为业务不同会对不同层次提供的接口采取不同的使用,比如非阻塞的网络IO。

C++服务端

接下来是实践,写了一个简单的echo服务为例。首先在echo.thrift中定义service如下:

service echo{
     string echo(1:string msg)
}

然后使用命令thrift -gen cpp echo.thrift和thrift -gen py echo.thrift分别生成c++和python版本的代码,python的用来做客户端。
然后修改生成的cpp目录gen-cpp之下的echo_server.skeleton.cpp,内容如下:

// This autogenerated skeleton file illustrates how to build a server.
// You should copy it to another filename to avoid overwriting it.

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

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

using boost::shared_ptr;

//using namespace ;

class echoHandler : virtual public echoIf {
 public:
  echoHandler() {
    // Your initialization goes here
  }

  void echo(std::string& _return, const std::string& msg) {
    // Your implementation goes here
   // printf("echo\n");
    std::cout << "get msg: " << msg << std::endl;  //主要就是这个函数的修改
    _return = msg;
  }

};

int main(int argc, char **argv) {
  int port = 9090;
  shared_ptr<echoHandler> handler(new echoHandler());
  shared_ptr<TProcessor> processor(new echoProcessor(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);
  server.serve();
  return 0;
}

之后编译,新手编译可能会遇到两个问题。第一个问题是找不到thrift,g++提示错误Thrift.h: No such file or directory,解决方法也简单,既然是找不到,那就把它添进去,加上g++编译选项 -I /usr/local/include/thrift -L /usr/local/lib,添加thrift的安装路径的头文件库和lib库。 第二个问题是提示error: ‘uint8_t’ does not name a type,解决办法也是加上编译选项-g -DHAVE_NETINET_IN_H,原因参考error:‘uint8_t’ does not name a type. 所以最后编译命令就是 g++ -g -DHAVE_NETINET_IN_H -I /usr/include/thrift -o server *.cpp -lthrift(lib看情况加不加),这样就生成的可执行文件server,server默认监听9090端口。

python客户端

python客户端比较简单,在gen-py目录中添加client.py文件,内容如下:

#!/usr/bin/env python
#coding:utf-8
import sys
sys.path.append('./')

from echo import echo #引入客户端类

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

try:
  #建立socket
  transport = TSocket.TSocket('localhost', 9090)
  #选择传输层,这块要和服务端的设置一致
  transport = TTransport.TBufferedTransport(transport)
  #选择传输协议,这个也要和服务端保持一致,否则无法通信
  protocol = TBinaryProtocol.TBinaryProtocol(transport)
  #创建客户端
  client = echo.Client(protocol)
  transport.open()

  while 1:
    msg = raw_input("input msg: ")
    msg_ret = client.echo(msg)
    print "echo: "+msg_ret

#  print "server - " + msg
  #关闭传输
  transport.close()
#捕获异常
except Thrift.TException, ex:
  print "%s" % (ex.message)

最后运行先运行server,之后执行python client.py能得到这样的结果,在server会收到信息,客户端输入的信息也得到回显。
客户端

input msg: show parameter
echo: show parameter
input msg:

服务端

get msg: show parameter

最后的内容大致如上所示,以后会慢慢写更加复杂的thrift的代码了。

posted @ 2017-09-08 14:27  scu_gqk  阅读(696)  评论(0编辑  收藏  举报