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

Boost.Beast SSL WebSocket服务器连接后报995:I/O操作中止

Boost.Asio/Beast SSL WebSocket服务器错误995(连接后立即断开)排查与解决

问题背景

使用Boost.Asio与Boost.Beast搭建带SSL的WebSocket服务器,客户端可成功建立连接但随即断开,报错:Read error: The I/O operation has been aborted because of either a thread exit or an application request (Code: 995)。服务器日志显示连接被正常接收并添加到ConnectionManager后触发该错误,已排查ConnectionManager跟踪正常、Ping保活启动、SSL上下文配置正确、监听端点正常。


1. 错误995的可能成因

  • 连接实例生命周期提前终止:SslWebSocket实例未被正确持有(比如用局部变量而非智能指针,或ConnectionManager的存储方式有误),导致异步async_read操作还在pending时实例被销毁,操作系统强制中止I/O操作。
  • IO上下文提前停止:io_context在异步操作完成前被调用stop(),或运行io_context的线程提前退出,所有未完成的异步操作都会被中止,触发995错误。
  • strand缺失导致并发冲突:WebSocket对象的异步操作(接受、读、Ping)未绑定到同一strand,引发并发访问WebSocket内部状态的未定义行为,间接导致连接被中止。
  • SSL握手未完成就启动读操作:日志显示"连接接受成功"仅代表TCP连接建立,SSL握手可能还在异步执行,此时提前调用async_read会导致操作异常中止。
  • Ping保活时机错误:在SSL握手完成前就发送Ping请求,导致连接被主动关闭,进而触发读操作的中止错误。

2. 线程/strand配置的解决办法

  • 为每个连接绑定专属strand:所有与SslWebSocket相关的异步操作(SSL握手、读、写、Ping)必须通过同一strand调度,确保串行执行,避免并发冲突。示例代码:
    // 在SslWebSocket类中初始化strand
    class SslWebSocket : public std::enable_shared_from_this<SslWebSocket> {
    public:
        explicit SslWebSocket(boost::asio::io_context& io_ctx, boost::asio::ssl::context& ssl_ctx)
            : ws_(io_ctx, ssl_ctx), strand_(io_ctx.get_executor()) {}
    
        void start_read() {
            // 通过strand调度读操作
            boost::asio::dispatch(strand_, [self = shared_from_this()]() {
                self->ws_.async_read(self->buffer_,
                    boost::beast::bind_front_handler(&SslWebSocket::on_read, self));
            });
        }
    
    private:
        boost::beast::ssl_stream<boost::beast::websocket::stream<boost::asio::ip::tcp::socket>> ws_;
        boost::asio::strand<boost::asio::io_context::executor_type> strand_;
        boost::beast::flat_buffer buffer_;
    };
    
  • 保证IO上下文线程池持续运行:在main函数中启动足够数量的线程运行io_context,且服务器停止前不终止这些线程:
    int main() {
        boost::asio::io_context io_context;
        boost::asio::ssl::context ssl_ctx(boost::asio::ssl::context::tlsv13_server);
        // 配置SSL上下文...
    
        WebSocketServer server(io_context, ssl_ctx, boost::asio::ip::tcp::endpoint{boost::asio::ip::make_address("0.0.0.0"), 8080});
        server.run();
    
        // 启动线程池运行io_context
        std::vector<std::thread> threads;
        for (size_t i = 0; i < std::thread::hardware_concurrency(); ++i) {
            threads.emplace_back([&io_context]() { io_context.run(); });
        }
    
        // 等待服务器停止信号(比如捕获SIGINT)
        // ...
    
        // 停止io_context并等待线程结束
        io_context.stop();
        for (auto& t : threads) {
            if (t.joinable()) t.join();
        }
    
        return 0;
    }
    
  • 用智能指针管理连接实例:ConnectionManager必须持有SslWebSocket的std::shared_ptr,确保异步操作期间实例不会被销毁。例如:
    class ConnectionManager {
    public:
        void add(std::shared_ptr<SslWebSocket> client) {
            std::lock_guard<std::mutex> lock(mutex_);
            clients_.insert(std::move(client));
        }
    
    private:
        std::mutex mutex_;
        std::unordered_set<std::shared_ptr<SslWebSocket>> clients_;
    };
    
  • 严格遵循SSL握手流程:在async_accept完成后,先执行异步SSL握手,仅在握手成功的回调中启动async_read和Ping保活机制:
    void do_accept() {
        acceptor_.async_accept(
            boost::asio::make_strand(io_context_),
            boost::beast::bind_front_handler(
                &WebSocketServer::on_accept,
                shared_from_this()));
    }
    
    void on_accept(boost::system::error_code ec, boost::asio::ip::tcp::socket socket) {
        if (!ec) {
            auto client = std::make_shared<SslWebSocket>(io_context_, ssl_ctx_);
            client->ws_.next_layer().swap(socket);
    
            // 启动异步SSL握手
            client->ws_.async_handshake(boost::beast::websocket::role_type::server, "/",
                boost::beast::bind_front_handler(
                    &WebSocketServer::on_handshake,
                    shared_from_this(),
                    client));
        }
        do_accept(); // 继续接受新连接
    }
    
    void on_handshake(boost::system::error_code ec, std::shared_ptr<SslWebSocket> client) {
        if (!ec) {
            connection_manager_.add(client);
            client->start_read(); // 握手成功后启动读操作
            client->start_ping(); // 启动Ping保活
        }
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 19:52:07