Boost.Asio async_receive在客户端关闭Socket时未返回的问题
问题原因与解决方案
问题根源
当客户端主动关闭TCP连接时,服务端的async_receive会返回0字节的读取结果,这是TCP连接正常关闭的标准信号。但你的代码存在两个关键问题:
- 未检查
async_receive的返回值,忽略了连接关闭的信号 - 依赖
stream.is_open()判断连接状态,该方法仅在socket被主动关闭或发生严重错误时才返回false,收到FIN包时socket仍处于"打开"状态(可发送数据),导致循环无法退出
修复后的代码
修改handle_connection函数,添加返回值检查和异常处理:
#include <boost/asio/co_spawn.hpp> #include <boost/asio/detached.hpp> #include <boost/asio/io_service.hpp> #include <boost/asio/ip/tcp.hpp> #include <boost/asio/awaitable.hpp> #include <boost/asio.hpp> #include <string> #include <iostream> using namespace std; namespace asio = boost::asio; using namespace boost::asio::ip; asio::awaitable<void> handle_connection(tcp::socket&& stream) { std::cout << "new connection\n"; std::string buffer; uint64_t buffer_size; try { while(true) { // 读取消息长度,检查返回值 size_t len = co_await stream.async_receive(asio::buffer(&buffer_size, 8), asio::use_awaitable); if(len == 0) { // 返回0表示连接已关闭 break; } buffer = std::string(buffer_size, '\0'); std::cout << "message size: " << buffer_size << "\n"; // 读取消息内容,同样检查返回值 len = co_await stream.async_receive(asio::buffer(buffer, buffer_size), asio::use_awaitable); if(len == 0) { break; } std::cout << "new message: " << buffer << "\n"; } } catch(const asio::system_error& e) { // 处理连接异常断开的情况 std::cout << "connection error: " << e.what() << "\n"; } // 主动关闭socket,释放资源 stream.close(); cout << "socket closed\n"; co_return; } asio::awaitable<void> accept_connection() { auto ex = co_await asio::this_coro::executor; boost::asio::ip::tcp::acceptor acceptor(ex, {{}, 8000}); tcp::socket sock = co_await acceptor.async_accept(asio::use_awaitable); while(true) { co_spawn(ex, handle_connection(std::move(sock)), asio::detached); sock = co_await acceptor.async_accept(asio::use_awaitable); } co_return; } int main() { asio::io_context io_ctx(2); co_spawn(io_ctx, accept_connection(), asio::detached); io_ctx.run(); }
关键修改点
- 移除
stream.is_open()的循环判断,改为检查async_receive的返回值:当返回0时立即退出循环 - 添加
try-catch块捕获asio::system_error,处理客户端强制断开连接(如直接杀死进程)的异常情况 - 循环结束后主动调用
stream.close(),确保socket资源被正确释放
内容的提问来源于stack exchange,提问作者kasra
相关产品推荐
相关产品推荐

