You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用boost::asio::use_future调用async_read时,如何获取EOF时的传输字节数?

使用Boost.Asio Future模式处理EOF时获取已传输字节数的问题

问题背景

为适配第三方库的阻塞式调用需求,我们基于Boost.Asio实现网络通信:用少量网络线程处理异步操作,第三方库通过专用线程调用Session::read方法。当前使用asio::async_read结合use_future实现异步转阻塞,但遇到对等端断开连接(触发boost::asio::error::eof)时,future会直接抛出异常,无法获取断开前已传输的字节数;而使用回调handler的方式,能同时拿到错误码和已传输字节数。

示例代码:

namespace ba = boost::asio;

int32_t Session::read (unsigned char* pBuffer, uint32_t bufferSizeToRead)
{
   // 创建可变缓冲区
   ba::mutable_buffer buffer (pBuffer, bufferSizeToRead);
   int32_t result = 0;

   // 发起异步读操作,通过future让调用线程阻塞等待结果
   std::future<std::size_t> future =
         ba::async_read(m_socket, buffer, ba::bind_executor(m_sessionStrand, ba::use_future));
   try
   {
      // 阻塞调用线程,直到异步读操作完成
      result = future.get();
   }
   catch (boost::system::system_error &ex)
   {
      auto exitCode = ex.code().value();
      if ( exitCode == ba::error::eof )
      {
         log ("Connection closed by the peer");
      }
   }

   return result;  // 发生EOF时此处返回0
}

存在两个疑问:

  • 使用future时,是否仍能获取已传输的字节数?
  • 是否有其他方案,既能提供阻塞式调用,又能使用asio::async_read或类似异步接口?

解答

1. Future模式下能否获取EOF时的已传输字节数?

直接使用ba::use_future无法实现。因为use_future的设计逻辑是:操作成功时将已传输字节数存入future;操作出错(包括EOF)时则抛出包含错误码的异常,不会携带任何部分结果。future本身只能传递单一的成功值或异常,无法同时返回错误状态和已传输字节数,这是该模式的固有局限性。

2. 替代方案:自定义Promise包装器

要同时满足阻塞式调用和获取EOF时的部分结果,可以自定义一个包含错误码和字节数的结果结构体,通过std::promise将两者绑定后传递给future,这样调用线程阻塞等待时能拿到完整的结果信息。

示例实现:

#include <boost/asio.hpp>
#include <future>

namespace ba = boost::asio;

// 自定义结果结构体,同时保存错误码和已传输字节数
struct ReadResult {
    boost::system::error_code ec;
    std::size_t bytes_transferred;
};

int32_t Session::read(unsigned char* pBuffer, uint32_t bufferSizeToRead)
{
    ba::mutable_buffer buffer(pBuffer, bufferSizeToRead);
    std::promise<ReadResult> read_promise;
    auto read_future = read_promise.get_future();

    // 发起异步读操作,用自定义handler打包结果到promise
    ba::async_read(m_socket, buffer, ba::bind_executor(m_sessionStrand,
        [promise = std::move(read_promise)](const boost::system::error_code& ec, std::size_t bytes) mutable {
            promise.set_value({ec, bytes});
        }));

    // 阻塞等待异步操作完成,获取完整结果
    auto result = read_future.get();

    if (result.ec) {
        if (result.ec == ba::error::eof) {
            log("Connection closed by the peer");
        }
        // 可根据需求处理其他错误类型
    }

    // 返回已传输字节数,即使发生EOF也能拿到有效数据
    return static_cast<int32_t>(result.bytes_transferred);
}

这个方案的核心是绕过use_future的限制,手动用std::promise传递包含错误和结果的复合结构体,既保留了异步操作的线程池资源复用特性,又能让调用线程以阻塞方式获取完整结果。

另外,也可以直接使用asio::read同步接口,但如果需要复用异步线程池的资源,自定义promise的方式更合适——它本质还是异步执行,只是调用线程阻塞等待,不会占用线程池中的工作线程。

内容的提问来源于stack exchange,提问作者sullyt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 16:40:39