zoukankan      html  css  js  c++  java
  • 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 文件
     
     
     
  • 相关阅读:
    安卓内存的优化
    tcp和udp区别
    安卓中线程之间的通信方式(如何避免ANR)
    ArrayList和LinkedList区别
    Jmeter之接口测试
    C# 解析嵌套json
    C# 微信服务号模板消息中如何换行
    C# 对图片进行缩放拖动
    C# 使用Graphics绘制图片时发生闪烁的问题
    C# DevExpress的RepositoryItem设置UseParentBackground属性的办法
  • 原文地址:https://www.cnblogs.com/JesseFang/p/4682251.html
Copyright © 2011-2022 走看看