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

使用独立asio库实现异步TCP服务器遇I/O中止错误求助

异步TCP服务器async_accept报错:I/O操作因线程退出或应用请求中止

我正尝试用独立于Boost的asio库实现异步TCP服务器,但调用acceptor的async_accept函数时,出现错误提示:‘The I/o operation has been aborted because of either a thread exit or an application requests’,进程无法继续执行。换过端口没用,但同步版本服务器能正常运行。

报错的startAsyncAccept函数代码

void startAsyncAccept()
{
    acceptor.async_accept(socket, [&](const asio::error_code& error)
        {
            if(!error)
            {
                std::cout << "Client is connected" << "\n";
                startAsyncRead();
            }
            else
            {
                
                std::cerr << "It is: " << error.message() << '\n';
                return 0;
                
            }
            startAsyncAccept();


        }
    );
    
}

完整异步服务器代码

class Server
{
public:
    Server(asio::io_context& io_context) : acceptor(io_context, asio::ip::tcp::endpoint(asio::ip::address::from_string("127.0.0.1"), 2000)), socket(io_context)
    {
        startAsyncAccept();
    }
    ~Server() {}
private:
    // Members
    asio::ip::tcp::acceptor acceptor;
    asio::ip::tcp::socket socket;
    asio::streambuf buffer;
    std::vector<asio::ip::tcp::socket> sockets;

    // Functions
    void startAsyncAccept()
    {
        acceptor.async_accept(socket, [&](const asio::error_code& error)
            {
                if(!error)
                {
                    std::cout << "Client is connected" << "\n";
                    startAsyncRead();
                }
                else
                {
                    
                    std::cerr << "It is: " << error.message() << '\n';
                    return 0;
                    
                }
                startAsyncAccept();


            }
        );
        
    }

    void startAsyncRead()
    {
        asio::async_read_until(socket, buffer, '\n', [&](const asio::error_code& error, size_t length)
            {
                if(!error)
                {
                    std::string message(asio::buffers_begin(buffer.data()), asio::buffers_begin(buffer.data()) + length);
                    std::cout << "Received from client: " << message;

                    for(auto& clients : sockets)
                    {
                        asio::async_write(clients, asio::buffer(message), [&](const asio::error_code& error, size_t length) 
                            {
                                if(error)
                                {
                                    std::cerr << "Failed to write to client: " << error.message() << "\n";
                                }
                            }
                        );
                    }
                    buffer.consume(length);
                    startAsyncRead();

                }
                else
                {
                    std::cout << "Client disconnected." << std::endl;
                    removeClient();
                }
            }
        );
    }

    void startAsyncWrite() 
    {
        asio::async_write(socket, asio::buffer("Connected to chat Server. \n"), [&](const asio::error_code& error, size_t length) 
            {
                if(error)
                {
                    std::cerr << "Failed to write to the client: " << error.message() << "\n";
                    removeClient();
                }
            }
        );
    }
    void removeClient()
    {
        auto it = std::find_if(sockets.begin(), sockets.end(),
            [&](const auto& client_socket)
            {
                return &client_socket == &socket;
            });

        if (it != sockets.end())
        {
            sockets.erase(it);
        }
    }


};

问题原因及修复方案

1. 回调中错误的return 0导致监听中断

异步回调lambda的返回类型是void,返回0属于语法错误;更关键的是,错误分支直接返回会跳过后续的startAsyncAccept()调用,服务器停止监听新连接。如果此时io_context没有其他待处理任务,会直接退出,触发I/O操作中止错误。

修复:将return 0改为return;,并且无论是否出错,都要重新调用startAsyncAccept()(仅在acceptor被主动关闭时停止):

void startAsyncAccept()
{
    acceptor.async_accept(socket, [&](const asio::error_code& error)
        {
            if(!error)
            {
                std::cout << "Client is connected" << "\n";
                // 转移socket到容器,避免被下一次accept覆盖
                sockets.push_back(std::move(socket));
                // 重新初始化socket用于下一次监听
                socket = asio::ip::tcp::socket(acceptor.get_executor().context());
                // 注意:此处需操作容器中刚加入的socket,而非成员变量socket
                startAsyncReadForClient(sockets.back());
            }
            else
            {
                std::cerr << "It is: " << error.message() << '\n';
                // acceptor被主动关闭时,停止监听
                if (error == asio::error::operation_aborted)
                    return;
            }
            // 持续监听新连接
            startAsyncAccept();
        }
    );
}

2. 成员变量socket被复用,导致旧连接失效

Server类用单个成员变量socket处理所有客户端连接,当第二个客户端连接时,async_accept会覆盖该socket,导致第一个客户端的连接被强制断开,进而触发I/O中止错误。

修复:

  • 每次accept成功后,将socket转移到sockets容器中,再重新创建新的socket用于下一次监听。
  • 为每个客户端单独维护socket和buffer,建议创建ClientSession类封装客户端的所有操作,避免共享成员变量。

3. startAsyncRead绑定错误的socket

当前startAsyncRead操作的是Server类的成员变量socket,但该socket在accept下一个客户端时会被覆盖,导致之前的客户端读操作失效。

修复:为每个客户端的socket单独启动读操作,比如新增startAsyncReadForClient函数并传入对应的socket:

void startAsyncReadForClient(asio::ip::tcp::socket& client_socket)
{
    auto buffer = std::make_shared<asio::streambuf>();
    asio::async_read_until(client_socket, *buffer, '\n', 
        [this, &client_socket, buffer](const asio::error_code& error, size_t length)
        {
            if(!error)
            {
                std::string message(asio::buffers_begin(buffer->data()), asio::buffers_begin(buffer->data()) + length);
                std::cout << "Received from client: " << message;

                for(auto& clients : sockets)
                {
                    asio::async_write(clients, asio::buffer(message), [](const asio::error_code& error, size_t) 
                        {
                            if(error)
                            {
                                std::cerr << "Failed to write to client: " << error.message() << "\n";
                            }
                        }
                    );
                }
                buffer->consume(length);
                startAsyncReadForClient(client_socket);
            }
            else
            {
                std::cout << "Client disconnected." << std::endl;
                removeClient(client_socket);
            }
        }
    );
}

void removeClient(asio::ip::tcp::socket& client_socket)
{
    auto it = std::find_if(sockets.begin(), sockets.end(),
        [&](auto& sock) { return &sock == &client_socket; });

    if (it != sockets.end())
    {
        sockets.erase(it);
    }
}

4. 确保io_context持续运行

在主函数中,需要保证io_context始终有工作任务,避免没有异步操作时进程退出。可以使用asio::io_context::work:

int main()
{
    asio::io_context io_context;
    asio::io_context::work work(io_context); // 防止io_context无任务时退出
    Server server(io_context);
    io_context.run();
    return 0;
}

内容的提问来源于stack exchange,提问作者Jésus Christophe

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 01:25:21