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

基于Asio独立版C++实现双线程异步读取双数据源的技术问询

双线程异步读取双数据源的Asio实现方案

你的需求完全可行,Asio的异步模型天生适合处理多并发IO任务,下面针对你的代码问题给出修正方向和完整实现:

原代码的核心问题

  • 全局缓冲区冲突:vBuffer是全局变量,两个socket的异步读取会同时写入这个缓冲区,导致数据被覆盖、输出混乱。
  • 第二个socket未启动读取:代码仅对socket1调用了getData1,socket2连接后没有触发异步读取逻辑。
  • io_context管理不当:context2没有设置work对象,调用run()后会因无待处理任务直接退出,对应线程也会结束。
  • 参数错误:getData2的参数是socket1,应改为socket2。
  • 阻塞等待不优雅:用std::this_thread::sleep_for强制等待不是Asio的正确用法,应依赖io_context的事件循环维持程序运行。

优化实现方案(单io_context多线程)

推荐使用单个io_context配合多线程运行,Asio的io_context本身线程安全,多个线程可同时调用run()处理异步任务,高效且代码简洁:

#include <iostream>
#include <memory>
#include <thread>
#include <vector>

#define ASIO_STANDALONE
#include <asio.hpp>
#include <asio/ts/buffer.hpp>
#include <asio/ts/internet.hpp>

// 为每个socket创建独立缓冲区,避免数据冲突
void getData(asio::ip::tcp::socket& socket, std::shared_ptr<std::vector<char>> buffer)
{
    socket.async_read_some(asio::buffer(buffer->data(), buffer->size()),
        [&, buffer](std::error_code ec, std::size_t length)
        {
            if (!ec)
            {
                std::cout << "\n\n从" << socket.remote_endpoint() << "读取 " << length << " bytes\n\n";
                for (std::size_t i = 0; i < length; ++i)
                    std::cout << (*buffer)[i];
                std::cout.flush();

                getData(socket, buffer); // 继续异步读取
            }
            else if (ec != asio::error::eof)
            {
                std::cout << "\n读取错误: " << ec.message() << std::endl;
            }
        }
    );
}

int main() {
    asio::error_code ec;
    asio::io_context context;

    // 用work对象保持io_context运行,直到手动停止
    asio::executor_work_guard<asio::io_context::executor_type> idleWork(context.get_executor());

    // 启动2个线程处理io_context的异步任务
    std::vector<std::thread> threads;
    for (int i = 0; i < 2; ++i)
    {
        threads.emplace_back([&]() { context.run(); });
    }

    // 初始化两个socket和端点
    asio::ip::tcp::endpoint endpoint1(asio::ip::make_address("51.38.81.49", ec), 80);
    asio::ip::tcp::endpoint endpoint2(asio::ip::make_address("127.0.0.1", ec), 80);

    asio::ip::tcp::socket socket1(context);
    asio::ip::tcp::socket socket2(context);

    // 连接第一个数据源
    socket1.connect(endpoint1, ec);
    if (ec)
    {
        std::cout << "连接端点1失败: " << ec.message() << std::endl;
    }
    else
    {
        std::cout << "成功连接端点1: " << endpoint1 << std::endl;
        // 分配独立缓冲区并启动异步读取
        auto buffer1 = std::make_shared<std::vector<char>>(2 * 1024);
        getData(socket1, buffer1);

        // 发送HTTP请求
        std::string request1 =
            "GET /index.html HTTP/1.1\r\n"
            "Host: example.com\r\n\r\n";
        socket1.write_some(asio::buffer(request1), ec);
    }

    // 连接第二个数据源
    socket2.connect(endpoint2, ec);
    if (ec)
    {
        std::cout << "连接端点2失败: " << ec.message() << std::endl;
    }
    else
    {
        std::cout << "成功连接端点2: " << endpoint2 << std::endl;
        // 分配独立缓冲区并启动异步读取
        auto buffer2 = std::make_shared<std::vector<char>>(2 * 1024);
        getData(socket2, buffer2);

        // 发送对应请求(根据实际需求调整)
        std::string request2 =
            "GET /some-path HTTP/1.1\r\n"
            "Host: localhost\r\n\r\n";
        socket2.write_some(asio::buffer(request2), ec);
    }

    // 等待用户输入后优雅退出
    std::cout << "\n按回车键退出..." << std::endl;
    std::cin.get();

    // 停止io_context并等待线程结束
    context.stop();
    for (auto& t : threads)
    {
        if (t.joinable())
            t.join();
    }

    return 0;
}

关键改进点说明

  • 独立缓冲区:用std::shared_ptr<std::vector<char>>为每个socket分配独立缓冲区,避免数据覆盖,同时保证缓冲区在异步操作生命周期内有效。
  • 单io_context多线程:一个io_context配合多线程处理所有异步任务,Asio会自动调度任务到空闲线程,效率更高。
  • 优雅退出:用executor_work_guard保持io_context运行,用户输入后手动停止context并等待线程结束,替代阻塞sleep。
  • 统一读取函数:合并getData1和getData2为通用函数,减少代码冗余。

可选方案(双io_context)

若坚持使用两个独立io_context,只需为每个context添加executor_work_guard,确保调用getData2(socket2)启动读取,同时为每个socket分配独立缓冲区即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 11:18:28