为何socket已接收数据,async_read_some()操作仍未执行?
问题排查与修复
你的代码里有几个关键问题,直接导致async_read_some的完成处理程序触发不了,连阻塞read()都读不到数据:
1. reading变量的逻辑完全错误
你用一个全局的reading布尔值控制读操作发起,第一个socket设置完异步读之后,reading就变成true,后面的循环根本不会再进入读操作的分支。就算某次读操作完成后把reading改回false,也只会给第一个socket重新发读请求,其他连接永远没机会触发读。这直接导致大部分连接的读操作根本没被发起,自然收不到数据。
2. 滥用io_context.restart()
每次poll()之后就调用restart()完全没必要,甚至是破坏性的。restart()只有在io_context彻底停止(比如run()跑完所有操作返回)的时候才需要用,用来重置状态以便再次运行。而poll()只是处理当前就绪的事件,之后io_context仍处于活跃状态,此时调用restart()会清空内部的异步操作状态,就算数据到达,io_context也不知道要触发对应的处理程序。
3. 所有连接共享同一个缓冲区
所有socket的读操作都用同一个message_buffer,就算读操作能触发,多个连接同时读的时候数据也会互相覆盖,结果全是乱的。
4. 仅支持单个连接
acceptingCounter设为1之后就不再发起新的async_accept,服务器只能接收一个客户端连接,这虽然不是当前读数据的直接问题,但也是明显的设计缺陷。
修复后的代码
#include <iostream> #include <array> #include <vector> #include <memory> #include <algorithm> #include <boost/asio.hpp> using tcp = boost::asio::ip::tcp; int main(int argc, char *argv[]) { boost::asio::io_context io_context; tcp::acceptor acceptor(io_context, tcp::endpoint(tcp::v4(), 1025)); std::vector<std::shared_ptr<tcp::socket>> active_sockets; // 递归发起异步接受,实现循环监听 auto do_accept = [&]() { auto sock = std::make_shared<tcp::socket>(io_context); acceptor.async_accept(*sock, [&, sock](boost::system::error_code ec) { if (!ec) { std::cout << "客户端连接:" << sock->remote_endpoint() << std::endl; active_sockets.push_back(sock); // 为每个连接分配独立缓冲区,避免数据冲突 auto buffer = std::make_shared<std::array<char, 2048>>(); // 定义读操作的回调,读完自动续读 auto do_read = [&, sock, buffer](boost::system::error_code ec, std::size_t bytes_read) { if (!ec) { // 处理读到的数据,这里简单打印 std::cout << "收到数据:" << std::string(buffer->data(), bytes_read) << std::endl; // 读完继续监听下一次数据 sock->async_read_some(boost::asio::buffer(*buffer), do_read); } else { // 连接断开或出错,从列表移除 auto it = std::find(active_sockets.begin(), active_sockets.end(), sock); if (it != active_sockets.end()) { active_sockets.erase(it); } std::cout << "连接关闭:" << ec.message() << std::endl; } }; // 发起第一次读操作 sock->async_read_some(boost::asio::buffer(*buffer), do_read); } // 不管这次接受成功与否,继续接受下一个连接 do_accept(); }); }; std::cout << "等待连接..." << std::endl; do_accept(); // 让io_context持续运行处理异步事件 io_context.run(); return 0; }
修复要点
- 用
std::shared_ptr管理socket和缓冲区,既避免内存泄漏,又保证异步回调中对象不会提前销毁。 - 循环接受连接:每次异步接受完成后立刻发起下一次,支持多个客户端同时连接。
- 每个连接用独立的缓冲区,彻底解决数据覆盖问题。
- 读操作完成后自动发起新的异步读,保持对客户端数据的持续监听。
- 用
io_context.run()替代你原来的循环poll()+restart(),让Boost.Asio自己管理异步事件的生命周期,这才是正确的用法。
内容的提问来源于stack exchange,提问作者sea
相关产品推荐
相关产品推荐

