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

Boost Beast调用http::async_write触发“The handle is invalid”错误

问题背景
  • 最初遇到The file handle supplied is invalid报错,排查确认是socket提前关闭导致,修复该问题后又出现The handle is invalid错误
  • 报错触发时,异步写回调的已传输字节参数t值为4KB,表现为第一个4KB数据块写入完成后,回调或socket进入异常状态
  • 若将异步接口http::async_write替换为同步http::write接口,程序运行完全正常

问题对应实现代码如下:

void BeastResponse::write(http::response<http::file_body> responseFile)
{
    std::cout << "BeastResponse while file write: " << this << std::endl;
 
    auto self = shared_from_this();

    http::async_write(m_stream, responseFile, [self](beast::error_code ec, std::size_t t)
    {
        if (ec)
        {
            std::cout << "File Write Failed" << ": " << ec.message() << std::endl;
            std::cout << t << std::endl;

        }
        else
        {
            std::cout << t << std::endl;
        };
    });
}
根因分析

核心诱因是待发送的responseFile对象生命周期没有覆盖整个异步写操作全程:

  1. responseFile是write函数的形参,属于函数局部对象。http::async_write是异步非阻塞接口,发起IO操作后会立刻返回,不会等待发送完成。当write函数执行结束退出作用域时,responseFile会被立刻析构,其内部持有的file_body对应的文件句柄会被系统回收关闭。
  2. 之所以能成功写入4KB后才报错,是因为异步操作发起时,初始的4KB数据块刚好被拷贝到socket发送缓冲区完成发送,后续操作需要继续从responseFile持有的文件句柄读取剩余数据时,该对象已经被析构、文件句柄已经失效,因此触发The handle is invalid报错。
  3. 同步http::write接口是阻塞执行的,会一直等到整个响应全部写入完成才会返回,这期间responseFile始终处于函数作用域内、没有被析构,内部文件句柄一直有效,因此不会触发该问题。

额外需要确认的点:代码中仅通过捕获self保证BeastResponse实例的生命周期,需要确认m_stream是BeastResponse的直接成员,不会在异步操作执行期间被提前销毁。

修复方案

将responseFile通过值捕获的方式传入异步回调,保证其生命周期和异步操作绑定,直到写操作完成后再析构。修复后代码示例:

void BeastResponse::write(http::response<http::file_body> responseFile)
{
    std::cout << "BeastResponse while file write: " << this << std::endl;
 
    auto self = shared_from_this();
    // 值捕获responseFile,保证其在异步操作完成前不会被析构
    http::async_write(m_stream, responseFile, [self, responseFile](beast::error_code ec, std::size_t t)
    {
        if (ec)
        {
            std::cout << "File Write Failed" << ": " << ec.message() << std::endl;
            std::cout << t << std::endl;
        }
        else
        {
            std::cout << t << std::endl;
        }
    });
}

注:所有基于Asio/Beast的异步IO操作,都要求操作依赖的缓冲区、消息、流对象的生命周期必须覆盖整个异步操作周期,直到回调触发后再释放,否则就会出现悬空引用、资源提前释放的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 22:39:19