TThreadedSelectorServer模式源码分析

本文解析了Thrift非阻塞服务器的工作流程,重点介绍了AbstractNonblockingServer和TThreadedSelectorServer类中的关键方法,如serve(), startThreads(), startListening()等,并详细解释了这些方法如何协同工作以实现服务器的连接接收与处理。

<span style="font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: rgb(255, 255, 255);">TThreadedSelectorServer extendsAbstractNonblockingServer</span>

AbstractNonblockingServer extends TServer

 

AbstractNonblockingServer中:

/**
   * Begin accepting connections and processing invocations.
   */
  public void serve() {
    // start any IO threads
    if (!startThreads()) {
      return;
    }
 
    // start listening, or exit
    if (!startListening()) {
      return;
    }
 
    setServing(true);
 
    // this will block while we serve
    waitForShutdown();
 
    setServing(false);
 
    // do a little cleanup
    stopListening();
  }

(1)startThreads()为虚函数,在TThreadedSelectorServer中会实现。其中:

(2)startListening():服务端开启transport监听。

/**
   * Have the server transport start accepting connections.
   *
   * @return true if we started listening successfully, false if something went
   *         wrong.
   */
  protected boolean startListening() {
    try {
      serverTransport_.listen();
      return true;
    } catch (TTransportException ttx) {
      LOGGER.error("Failed to start listening on server socket!", ttx);
      return false;
    }
  }


(3)setServing(true); 设置服务器工作状态为true

(4)waitForShutdown(); 服务运行时,该方法及以下方法将阻塞。A method that will block until when threads handling the servinghave been shut down.

(5)setServing(false); 设置服务器工作状态为false

(6)stopListening(); 服务端关闭transport监听。Stop listening for connections.

 

继续看TThreadedSelectorServer的startThreads方法。


/**
   * Start the accept and selector threads running to deal with clients.
   *
   * @return true if everything went ok, false if we couldn't start for some
   *         reason.
   */
  @Override
  protected boolean startThreads() {
    try {
      for (int i = 0; i < args.selectorThreads; ++i) {
        selectorThreads.add(new SelectorThread(args.acceptQueueSizePerThread));
      }
      acceptThread = new AcceptThread((TNonblockingServerTransport) serverTransport_,
        createSelectorThreadLoadBalancer(selectorThreads));
      for (SelectorThread thread : selectorThreads) {
        thread.start();
      }
      acceptThread.start();
      return true;
    } catch (IOException e) {
      LOGGER.error("Failed to start threads!", e);
      return false;
    }
  }

SelectorThread:TheSelectorThread(s) will be doing all the selecting on accepted active connections.上面需要注意的SelectorThread和AcceptThread。

AcceptThread:The thread thatselects on the server transport (listen socket) and accepts new connections tohand off to the IO selector threads。

SelectorThread线程启动后,做如下事情:

/**
     * The work loop. Handles selecting (read/write IO), dispatching, and
     * managing the selection preferences of all existing connections.
     */
    public void run() {
      try {
        while (!stopped_) {
          select();
          processAcceptedConnections();
          processInterestChanges();
        }
        for (SelectionKey selectionKey : selector.keys()) {
          cleanupSelectionKey(selectionKey);
        }
      } catch (Throwable t) {
        LOGGER.error("run() exiting due to uncaught error", t);
      } finally {
        // This will wake up the accept thread and the other selector threads
        TThreadedSelectorServer.this.stop();
      }
    }

来看select方法:

/**
     * Select and process IO events appropriately: If there are existing
     * connections with data waiting to be read, read it, buffering until a
     * whole frame has been read. If there are any pending responses, buffer
     * them until their target client is available, and then send the data.
     */
    private void select() {
      try {
        // wait for io events.
        selector.select();

        // process the io events we received
        Iterator<SelectionKey> selectedKeys = selector.selectedKeys().iterator();
        while (!stopped_ && selectedKeys.hasNext()) {
          SelectionKey key = selectedKeys.next();
          selectedKeys.remove();

          // skip if not valid
          if (!key.isValid()) {
            cleanupSelectionKey(key);
            continue;
          }

          if (key.isReadable()) {
            // deal with reads
            handleRead(key);
          } else if (key.isWritable()) {
            // deal with writes
            handleWrite(key);
          } else {
            LOGGER.warn("Unexpected state in select! " + key.interestOps());
          }
        }
      } catch (IOException e) {
        LOGGER.warn("Got an IOException while selecting!", e);
      }
    }


这里主要是用到java的nio技术来处理。

若等到读事件则处理读,等到写事件则处理写。

<think>我们正在处理关于Thrift 0.15.0中TThreadedSelectorServer::Args缺失的问题。 根据之前的回答,在Thrift 0.15.0中,已经移除了带有`::Args`后缀的命名方式。 因此,对于TThreadedSelectorServer,同样也不再使用`TThreadedSelectorServer::Args`,而是使用新的命名规范。 需要说明: 1. 在旧版本中,我们可能会使用`TThreadedSelectorServer::Args`来设置服务器的参数。 2. 在新版本中,参数结构体的命名方式已经改变,不再使用`::Args`这样的嵌套结构。 具体到TThreadedSelectorServer,我们通常会创建一个参数对象,然后用于初始化服务器。在0.15.0版本中,应该使用`TThreadedSelectorServer::TArgs`或者直接是一个结构体(具体取决于代码生成)。 但是,请注意:Thrift的服务器类通常有一个内部结构体(或类)用于参数,在0.15.0版本中,这个结构体的命名可能是`TArgs`(不带`::Args`后缀的嵌套类型)。因此,你需要使用`TThreadedSelectorServer::TArgs`。 例如,在0.15.0中,你可能会这样写: ```cpp // 创建服务器参数对象 apache::thrift::concurrency::TThreadedSelectorServer::TArgs args; args.port = 9090; // 设置其他参数... // 然后创建服务器 TThreadedSelectorServer server(myProcessor, args); ``` 注意:在0.15.0中,`TThreadedSelectorServer`的参数结构体是`TArgs`,它是一个嵌套在`TThreadedSelectorServer`类中的结构体。因此,正确的使用方式是`TThreadedSelectorServer::TArgs`。 所以,如果你在代码中遇到了`TThreadedSelectorServer::Args`,需要将其改为`TThreadedSelectorServer::TArgs`。 总结:Thrift 0.15.0中,`TThreadedSelectorServer::Args`已被替换为`TThreadedSelectorServer::TArgs`。 接下来,按照要求提出3-5个相关问题。 </think>在 Thrift 0.15.0 中,`TThreadedSelectorServer::Args` 已被弃用并移除。以下是替代方案和关键变更: ### 关键变更说明 1. **参数传递方式重构** 旧版使用嵌套结构体: ```cpp // 0.13.0 及更早版本用法(已失效) TThreadedSelectorServer::Args args; args.port = 9090; auto server = std::make_shared<TThreadedSelectorServer>(processor, args); ``` **0.15.0 新版直接传递参数**: ```cpp // 正确用法:直接构造服务器对象 auto server = std::make_shared<TThreadedSelectorServer>( processor, // Processor 9090, // 端口 std::make_shared<BufferedTransportFactory>(), std::make_shared<BinaryProtocolFactory>() ); ``` 2. **移除 Args 结构体的原因** - 简化 API 设计,减少冗余封装 - 提升性能(避免参数结构体的额外拷贝) - 统一构造函数签名,与其他服务器类(如 `TSimpleServer`)保持一致 3. **参数设置替代方案** 需通过构造函数直接设置核心参数: ```cpp auto server = new TThreadedSelectorServer( processor, // 必需: 请求处理器 port, // 必需: 监听端口 transportFactory, // 必需: 传输层工厂 protocolFactory, // 必需: 协议工厂 threadManager, // 可选: 线程管理器(默认自动创建) numIOThreads // 可选: I/O 线程数(默认=4) ); ``` ### 迁移注意事项 - **编译错误处理**:将 `TThreadedSelectorServer::Args` 替换为直接参数列表 - **线程配置**:线程数通过 `numIOThreads` 参数设置(替代原 `args.nThreads`) - **高级配置**:使用 `TThreadedSelectorServerSettings` 结构体(独立于 `::Args`)进行细粒度调优
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值