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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 21:48:23