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

独立ASIO中async_write完成句柄未被io_context调用问题求助

调试独立ASIO单线程TCP客户端异步写完成句柄不触发问题

问题描述

调试基于独立ASIO(非Boost版本)开发的单线程TCP客户端应用时遇到异常:调用asio::async_write后,后端服务器能正常接收数据,但该异步写操作的完成句柄未被io_context.run()或io_context.poll()触发执行。已确认io_context与socket均有效,socket.is_open()返回true。

代码示例

network.h

class Network
{
public:
    Network();
    void ConnectToServer();
    void Update();
    void Test(std::string input);

private:
    asio::io_context io_context;
    asio::ip::tcp::socket socket;
    asio::ip::basic_resolver_results<asio::ip::tcp> endpoints;
};  

network.cpp

Network::Network() : socket(io_context)
{
    asio::ip::tcp::resolver resolver(io_context);
    endpoints = resolver.resolve(serverIP, serverPort); // ip和port是定义好的静态变量
}

void Network::ConnectToServer()
{
    asio::connect(socket, endpoints);

    std::string initMessage = "I just connected";
    asio::write(socket, asio::buffer(initMessage));

    asio::streambuf receiveBuffer;
    asio::read_until(socket, receiveBuffer, "\n");
    std::istream responseStream(&receiveBuffer);

    std::string response;
    std::getline(responseStream, response);
    print("server response: " + response);
}

void Network::Update()
{
    print("about to poll");
    io_context.poll();
    print("just polled");
}

void Network::Test(std::string input)
{
    print("about to async_write");
    asio::async_write(socket, asio::buffer(input), [](const asio::error_code &ec, std::size_t bytes_transferred)
                      { 
                        try{
                            print("async_write completed no error");
                        }
                        catch(const std::exception& e)
                        {
                            print("async_write ERROR");
                        } });
    print("after async_write call");
}

main.cpp

Network *network;

int main(void)
{
    // 其他单线程逻辑
    network = new Network();
    network->ConnectToServer();
    network->Test("hello");
    // 其他单线程逻辑
    print("main loop starting");
    while(true) // 实际是!glfwWindowShouldClose(window),基于GLFW的应用
    {
        // 其他单线程逻辑
        network->Update();
        if(有玩家输入)
        {
            print("player input");
            network->Test("in main loop");
        }
        // 其他单线程逻辑
    }
}

运行日志

about to connect to server
connected to server
server response: You connected successfully
about to async_write
after async_write call
main loop starting
about to poll
async_write completed no error
just polled
about to poll
just polled
...
player input
about to async_write
after async_write call
about to poll
just polled
...

调试思路建议

  • 检查缓冲区生命周期:asio::async_write使用的asio::buffer(input)依赖于Test函数的参数input,当Test执行完毕返回后,input会被销毁,导致缓冲区失效。即使服务器收到数据,ASIO在触发完成句柄时可能因访问已释放内存而异常(未被捕获)。建议将待发送数据改为类成员变量,或用std::shared_ptr持有,确保缓冲区在异步操作完成前始终有效。
  • 完善完成句柄的错误处理:当前完成句柄仅捕获std::exception,但ASIO的错误通过error_code参数传递而非抛出异常。应在句柄开头检查ec状态,打印ec.message()确认是否存在未被发现的错误,比如:
    [](const asio::error_code &ec, std::size_t bytes_transferred)
    { 
        if (ec) {
            print("async_write error: " + ec.message());
            return;
        }
        print("async_write completed, bytes: " + std::to_string(bytes_transferred));
    }
    
  • 确保io_context任务被充分处理:io_context.poll()仅处理当前就绪的任务,若异步写的完成事件尚未就绪就会直接返回。可尝试在Update()中循环调用poll_one()直到无任务可处理,或改用io_context.run_for(std::chrono::milliseconds(1)),确保所有就绪任务都被执行。
  • 添加executor_work_guard维持io_context活性:若io_context在无待处理任务时进入idle状态,可能导致后续异步操作无法被调度。在Network类中添加asio::executor_work_guard<asio::io_context::executor_type>成员,构造时用asio::make_work_guard(io_context)初始化,保证io_context始终处于可调度状态。
  • 排查socket内部状态:尽管socket.is_open()返回true,仍可能存在未处理的错误状态。可在调用async_write前,用带error_code参数的接口检查socket状态,比如:
    asio::error_code ec;
    bool is_open = socket.is_open(ec);
    if (!is_open || ec) {
        print("socket state error: " + ec.message());
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 21:16:09