thrift TNonblockingServer 使用

下载 0.9.1 版本 (0.9.2需要 2.5的bison,而 RHEL6上自带bison是2.4)

TNonblockingServer 时必须使用 TFramedTransport ,不能使用 TBufferedTransport,因为前者会先写入这个消息的字节数。这样非阻塞时可以预知消息的大小。

1. 服务端获取请求方的IP

网上流传最多的是扩展

bool TDispatchProcessor::process(boost::shared_ptr<protocol::TProtocol> in,

boost::shared_ptr<protocol::TProtocol> out,

void* connectionContext)

从 in 获得 transport 然后获得 TSocket 对象。但这个方法只适合阻塞式的 TSimpleServer 和 TThreadPoolServer 等,并不适合 TNonblockingServer。使用 TNonblockingServer 时,可通过扩展 void TServerEventHandler::processContext(void* serverContext, boost::shared_ptr<TTransport> transport) ,这里 transport 参数是个 TSocket 对象,而这个函数总会在调用 processor 处理请求之前被调用。

static boost::thread_specific_ptr<std::string> thrift_client_ip; // thread specific
class MyServerEventHandler : public TServerEventHandler
{
    virtual void processContext(void* serverContext, boost::shared_ptr<TTransport> transport)
    {
        TSocket *sock = static_cast<TSocket *>(transport.get());

        if (sock)
        {
            //thrift_client_ip.reset(new string(sock->getPeerAddress())); // 0.9.2, 复用 TNonblockingServer::TConnection 导致 getPeerAddress() 返回脏数据, 见 https://issues.apache.org/jira/browse/THRIFT-3270
            sock->getCachedAddress(); // use this api instead
        }
    }
};

// create nonblocking server
TNonblockingServer server(processor, protocolFactory, port, threadManager);
boost::shared_ptr<MyServerEventHandler> eventHandler(new MyServerEventHandler());
server.setServerEventHandler(eventHandler);

TNonblockingServer 复用 TNonblockingServer::TConnection 对象,但调用 TSocket::setCachedAddress() 并没有清掉 peerAddress_ 和 peerHost_ ,导致脏数据。

需要 TSocket::setCachedAddress() 函数中清除 这2个变量

lib/cpp/src/thrift/transport/TSocket.cpp

void TSocket::setCachedAddress(const sockaddr* addr, socklen_t len) {
  if (!path_.empty()) {
    return;
  }

  switch (addr->sa_family) {
  case AF_INET:
    if (len == sizeof(sockaddr_in)) {
      memcpy((void*)&cachedPeerAddr_.ipv4, (void*)addr, len);
    }
    break;

  case AF_INET6:
    if (len == sizeof(sockaddr_in6)) {
      memcpy((void*)&cachedPeerAddr_.ipv6, (void*)addr, len);
    }
    break;
  }
  peerAddress_.clear(); // ++
  peerHost_.clear(); // ++
}

2. 禁用监听 IPv6

阻塞式服务需要修改 lib/cpp/src/thrift/transport/TServerSocket.cpp 的

TServerSocket::listen() 函数,修改 hints.ai_family = PF_INET;

而 TNonblockingServer 需要修改 lib/cpp/src/thrift/transport/TNonblockingServer.cpp

TNonblockingServer::createAndListenOnSocket() 函数,修改 hints.ai_family = PF_INET;

3. 切换 libevent 为 libev

由于项目中用到了 libev,而 thrift 的 TNonblockingServer 用到 libevent,而它们头文件有名字冲突。libev 做了个简单的 libevent 适配接口,但 thrift 还用到了 创建 socketpair 设置 socket close on exec 等函数,我简单的从 libevent 拷贝过来,即编译成功。 (sockepair 本来理论上可以用 libev 的 ev_async 替代的,但由于这里 thrift 直接把 TConnection 的指针通过 socket 传递,有个队列的功能在里面了,稍花时间就没做)

因为前面 TNonblockingServer 复用 TConnection 和 TSocket 导致TSocket::getPeerAddress() 脏数据,需要修改 TSocket 源码,为了更好的发布,我把 TNonblockingServer 单独提到项目中,并直接禁用了复用 TConnection ,这样使用默认 thrift 库即可。

修改后的 TNonblockingServer文件

时间: 2024-09-20 19:31:33

thrift TNonblockingServer 使用的相关文章

thrift

基本类型 bool :布尔类型( true or value),占一个字节 byte:有符号字节 i16:16位有符号整型 i32:32位有符号整型 i64:64位有符号整型 double :64位浮点数 string:未知编码或者二进制的字符串 注意,thrift不支持无符号整型,因为很多目标语言不存在无符号整型(如java). 支持的传输格式 * TBinaryProtocol : 二进制编码格式进行数据传输.    * TCompactProtocol : 这种协议非常有效的,使用Vari

使用Thrift RPC编写程序(服务端和客户端)

1. Thrift类介绍 Thrift代码包(位于thrift-0.6.1/lib/cpp/src)有以下几个目录: concurrency:并发和时钟管理方面的库processor:Processor相关类protocal:Protocal相关类transport:transport相关类server:server相关类 1.1 Transport类(how is transmitted?)负责数据传输,有以下几个可用类:TFileTransport:文件(日志)传输类,允许client将文件

Thrift0.9.3 C++版代码阅读随笔——TNonblockingServer

0.一些参考资料 (参考资料1)对thrift的一个基本介绍可以参考: http://wenku.baidu.com/link?url=LLL5H3qL4hJ3o6dfq0SBgztqtxYFR5vDyftwowKNRMWiIQ3t87mCu-GMZljxcZVryxxhqna1hM4eu3F7AyCMlC7fFy7yWl18IIl6nY7JKca (参考资料2)thrift IDL定义可参考(就是定义结构化数据和服务的方法): http://diwakergupta.github.io/thr

RPC原理与实践(二)----Thrift分层模型

这一节我们从一下几个方面来讲一下Thrift的分层架构,按照官方的定义这是Thrift的网络栈,其中网络栈中分为一下几个部分,(由栈顶到栈底)server,processor,protocol,transport.下面我们按照这种结构来了解一下thrift. Transport层: 由于涉及到网络之间的数据传输,所以Thrift支持多种网络传输协议,比如TCP,HTTP等.Thrift Transport都是基于TCP/IP的,而底层都是通过socket来实现的.Transport层的作用是封装

ubuntu thrift 0.9.3编译安装

Table of Contents 1. 下载thrift源代码 2. 编译并安装 3. 运行测试程序 4. 安装 1 下载thrift源代码 git clone https://git-wip-us.apache.org/repos/asf/thrift.git thrift git checkout 0.9.3 2 编译并安装 安装依赖 apt-get install automake apt-get install libssl-dev apt-get install byacc apt-

Thrift框架介绍

1.前言 Thrift是一个跨语言的服务部署框架,最初由Facebook于2007年开发,2008年进入Apache开源项目.Thrift通过一个中间语言(IDL, 接口定义语言)来定义RPC的接口和数据类型,然后通过一个编译器生成不同语言的代码(目前支持C++,Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, Smalltalk和OCaml),并由生成的代码负责RPC协议层和传输层的实现. 2.架构 Thrift实际上是实现了

thrift框架总结,可伸缩的跨语言服务开发框架

thrift框架总结,可伸缩的跨语言服务开发框架 前言: 目前流行的服务调用方式有很多种,例如基于 SOAP 消息格式的 Web Service,基于 JSON 消息格式的 RESTful 服务等.其中所用到的数据传输方式包括 XML,JSON 等,然而 XML 相对体积太大,传输效率低,JSON 体积较小,新颖,但还不够完善.本文将介绍由 Facebook 开发的远程服务调用框架 Apache Thrift,它采用接口描述语言定义并创建服务,支持可扩展的跨语言服务开发,所包含的代码生成引擎可以

thrift实例

Thrift实例 Apache thrift是 Facebook 实现的一种高效的.支持多种编程语言的远程服务调用的框架. 它采用接口描述语言定义并创建服务,支持可扩展的跨语言服务开发,所包含的代码生成引擎可以在多种语言中,如 C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, Smalltalk 等创建高效的.无缝的服务,其传输数据采用二进制格式,相对 XML 和 JSON 体积更小,对于高并发.大数据量和多语言的环境

Thrift安装介绍

一.简介 1.语言库要求 因为thrift支持多语言.所以编译thrift源代码的过程中,会用到该语言的一些类库.如c++的boost.java的jdk等. 那么,在安装thrift过程中,须要对各种语言安装哪些类库和工具呢,官方对此有具体的介绍: 所需语言库和工具 C++ :Boost 1.33.1+ (必选),libevent (可选,用来创建非堵塞server) ,zlib (可选) Java :Java 1.5+ (必选),Apache Ant (必选),Apache Ivy(必选),A