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

优化基于Boost.Async Beast的异步服务器浏览器响应延迟问题——是否可采用read_some方法?

问题描述

我基于Boost.Asio Beast实现了一个异步代理服务器,工作流程是:接收浏览器请求后,建立第二个Socket连接到目标服务器,异步写入请求,等拿到目标服务器的响应后,再异步返回给浏览器。目前的问题是,触发向浏览器返回响应的on_read函数存在较长延迟,导致浏览器等待时间久。相关核心代码如下:

void on_write( boost::system::error_code ec, std::size_t bytes_transferred) {
    boost::ignore_unused(bytes_transferred);
    if(ec) return fail2(ec, "write");
    std::cout << "===========on_write============" << std::endl;
    stopper("async_write" , 0);
    stopper("on_write" , 1);
    // Receive the HTTP response
    http::async_read(redirect_stream_, redirect_buffer_, redirect_res_,
        std::bind( &session2::on_read, shared_from_this(),
            std::placeholders::_1, std::placeholders::_2));
}
void on_read( boost::system::error_code ec, std::size_t bytes_transferred) {
    boost::ignore_unused(bytes_transferred);
    if(ec) return fail2(ec, "read");
    std::cout << "===========on_read============" << std::endl;
    stopper("on_write" , 0);
    stopper("on_read" , 1);
    // Write the message to standard out
    std::cout << redirect_res_.base() << std::endl;
    http::async_write(stream_, redirect_res_,
        std::bind( &session2::start_shutdown, shared_from_this(),
            std::placeholders::_1, std::placeholders::_2));
    // Gracefully close the stream
}

想请教:有没有更优方案缩短浏览器响应时间?是否可以用read_some方法来优化?


解决方案

嘿,这个场景我太熟了——异步代理的延迟优化核心就是不要等完整响应接收完再回传,咱们一步步拆解:

1. 关于read_some的可行性

答案是肯定的,但不能直接替换http::async_read,因为HTTP是结构化协议,read_some只能拿到原始字节流,没法直接解析响应格式。不过Beast提供了更灵活的方式:用http::parser分块读取+即时回传,每解析出一部分数据就立刻写给浏览器,让浏览器不用等完整响应就能开始处理,感知延迟会大幅降低。

核心思路的代码示例如下:

// 把成员变量里的redirect_res_换成parser
http::response_parser<http::string_body> redirect_parser_;
bool header_sent_ = false;

void on_write(boost::system::error_code ec, std::size_t bytes_transferred) {
    boost::ignore_unused(bytes_transferred);
    if(ec) return fail2(ec, "write");
    std::cout << "===========on_write============" << std::endl;
    stopper("async_write" , 0);
    stopper("on_write" , 1);
    
    // 改用async_read_some分批读取数据
    redirect_stream_.async_read_some(redirect_buffer_.prepare(8192),
        std::bind(&session2::on_read_some, shared_from_this(),
            std::placeholders::_1, std::placeholders::_2));
}

void on_read_some(boost::system::error_code ec, std::size_t bytes_read) {
    if(ec) {
        if(ec != boost::asio::error::eof) fail2(ec, "read_some");
        // 读取结束,处理收尾
        start_shutdown(boost::system::error_code{}, 0);
        return;
    }

    redirect_buffer_.commit(bytes_read);
    boost::system::error_code parse_ec;
    // 解析已读取的字节
    auto parsed_bytes = redirect_parser_.put(redirect_buffer_.data(), parse_ec);
    redirect_buffer_.consume(parsed_bytes);

    if(parse_ec) {
        fail2(parse_ec, "parse");
        return;
    }

    auto& response = redirect_parser_.get();
    // 先回传响应头部(只传一次)
    if(!header_sent_ && redirect_parser_.got_header()) {
        http::async_write(stream_, response.base(),
            std::bind(&session2::on_write_to_browser, shared_from_this(),
                std::placeholders::_1, std::placeholders::_2));
        header_sent_ = true;
    }

    // 回传已接收的body分段,避免重复发送
    if(!response.body().empty()) {
        std::string chunk = std::move(response.body());
        http::async_write(stream_, http::buffer(chunk),
            std::bind(&session2::on_write_to_browser, shared_from_this(),
                std::placeholders::_1, std::placeholders::_2));
    }

    // 继续读取下一批数据
    redirect_stream_.async_read_some(redirect_buffer_.prepare(8192),
        std::bind(&session2::on_read_some, shared_from_this(),
            std::placeholders::_1, std::placeholders::_2));
}

void on_write_to_browser(boost::system::error_code ec, std::size_t bytes_transferred) {
    boost::ignore_unused(bytes_transferred);
    if(ec) fail2(ec, "write_to_browser");
    // 写入完成后无需额外操作,等待下一次读取回调即可
}

2. 其他降低延迟的优化点

  • 调整缓冲区大小:用8192或16384字节的缓冲区,减少系统调用次数,提升读写效率。
  • 禁用Nagle算法:给redirect_stream_的socket设置boost::asio::ip::tcp::no_delay(true),减少TCP小包的合并延迟,尤其适合低带宽高延迟的网络场景。
  • 移除同步操作:你代码里的std::cout << redirect_res_.base() << std::endl;是同步IO,高并发下会拖慢回调执行,建议换成异步日志或直接移除调试输出。
  • 复用TCP连接:如果代理频繁和同一目标服务器通信,实现连接池复用已建立的连接,省去TCP三次握手的时间开销。

3. 原有方案延迟高的原因

你当前用http::async_read会等待完整的HTTP响应被接收并解析完毕才触发on_read,再开始写回浏览器。如果目标服务器返回大体积响应(比如大文件、长文本),浏览器要等很久才能收到第一个字节,感知到的自然就是高延迟。而分块回传的“边读边写”模式,能让浏览器提前接收数据,大幅优化体验。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 11:19:08