如何将boost::asio::tcp::io_stream关联到已有io_service?
解决boost::asio::ip::tcp::io_stream共享外部io_service/线程池的问题
嘿,我太懂这种“用惯了顺手的模式,突然碰到新类不兼容”的别扭感了——之前一直用外部io_service构造tcp::socket,让所有套接字共用一个线程池,管理起来特别省心,现在换成tcp::io_stream却发现没法直接绑定外部io_service,默认用内部初始化的实例,确实头疼。
不过别担心,咱们可以绕开这个限制,核心思路是:tcp::io_stream本质是对tcp::socket的流包装,只要让它底层的套接字绑定咱们的共享io_service就行。
具体实现步骤
- 先构造一个使用共享
io_service的tcp::socket实例; - 通过移动语义把这个套接字的所有权转移给
tcp::io_stream; - 之后
tcp::io_stream的所有异步操作都会委托给底层套接字,自然就跑在咱们的共享线程池里了。
代码示例
#include <boost/asio.hpp> #include <iostream> #include <vector> #include <thread> int main() { // 初始化共享的io_service和线程池 boost::asio::io_service shared_io; std::vector<std::thread> thread_pool; // 根据CPU核心数启动线程 const auto thread_count = std::thread::hardware_concurrency(); for (size_t i = 0; i < thread_count; ++i) { thread_pool.emplace_back([&shared_io]() { shared_io.run(); }); } // 1. 构造绑定共享io_service的tcp::socket boost::asio::ip::tcp::socket sock(shared_io); boost::asio::ip::tcp::resolver resolver(shared_io); const auto endpoints = resolver.resolve("example.com", "http"); // 异步连接示例 boost::asio::async_connect(sock, endpoints, [&shared_io](const boost::system::error_code& ec, boost::asio::ip::tcp::endpoint) { if (ec) { std::cerr << "Connect failed: " << ec.message() << std::endl; return; } // 2. 把套接字移动给tcp::io_stream boost::asio::ip::tcp::io_stream stream(std::move(sock)); // 3. 用stream执行异步操作,自动复用共享线程池 std::array<char, 1024> buffer; stream.async_read_some(boost::asio::buffer(buffer), [&stream, &buffer](const boost::system::error_code& ec, std::size_t bytes_read) { if (!ec) { std::cout << "Received data:\n" << std::string(buffer.data(), bytes_read) << std::endl; } stream.close(); }); }); // 等待所有异步任务完成 shared_io.run(); for (auto& t : thread_pool) { if (t.joinable()) { t.join(); } } return 0; }
关键说明
- 移动套接字后,原来的
sock实例就失效了,不能再操作它; tcp::io_stream的所有异步方法(比如async_read_some、async_write_some)最终都会调用底层套接字的对应方法,所以会自动使用共享的io_service;- 如果用的是新版Boost.Asio(使用
io_context替代io_service),代码逻辑完全一致,只需要替换类型名即可。
内容的提问来源于stack exchange,提问作者Stewart
相关产品推荐
相关产品推荐

