使用Boost.Beast建立SSL WebSocket连接需多次async_handshake?
Boost.Beast SSL WebSocket连接实现疑问
我在使用Boost.Beast和Boost.Asio建立带SSL的WebSocket连接时遇到问题:只有同时调用beast::websocket::stream及其SSL next_layer()的async_handshake,连接才能正常工作。若仅调用ws的handshake,会报错‘uninitialized (SSL routines)’。想确认此做法是否为正确标准的实现方式,寻求相关见解与建议。
相关代码
// Relevant part of the code class WebSocketClient : public std::enable_shared_from_this<WebSocketClient> { public: // ... (other members) void onConnect(const boost::system::error_code& ec, const tcp::endpoint&) { if (!ec) { // WebSocket initialization ws_ = beast::websocket::stream<ssl::stream<beast::tcp_stream>>(io_context_, ssl_context_); // This version works for me, but is it correct? ws_.next_layer().async_handshake(ssl::stream_base::client, std::bind(&WebSocketClient::onSslHandshake, shared_from_this(), std::placeholders::_1)); // Perform WebSocket handshake asynchronously ws_.async_handshake(host_, target_, "/", std::bind(&WebSocketClient::onHandshake, shared_from_this(), std::placeholders::_1)); } else { std::cerr << "Connection error: " << ec.message() << std::endl; } } // ... (other methods) private: asio::io_context& io_context_; ssl::context& ssl_context_; beast::websocket::stream<ssl::stream<beast::tcp_stream>> ws_; std::string host_; std::string target_; // ... (other members) };
解答
你的当前实现存在严重问题:同时发起SSL异步握手和WebSocket异步握手是错误的,这属于并发操作底层IO流,会导致未定义行为,只是碰巧在你的环境中暂时“工作”了。
错误原因
当你直接调用ws_.async_handshake()时,底层的SSL流还未完成握手初始化,处于未就绪状态,因此会抛出‘uninitialized (SSL routines)’错误。而你同时发起两个异步操作时,只是运气好让SSL握手先完成了,但这种依赖执行顺序的写法完全不可靠,在不同环境或负载下必然会出问题。
正确的标准流程
带SSL的WebSocket连接必须遵循严格的顺序:
- 完成TCP连接
- 先完成SSL层的握手(确保加密通道建立)
- 再执行WebSocket协议的握手
修正后的代码示例
void onConnect(const boost::system::error_code& ec, const tcp::endpoint&) { if (!ec) { ws_ = beast::websocket::stream<ssl::stream<beast::tcp_stream>>(io_context_, ssl_context_); // 先发起SSL异步握手,完成后再执行WS握手 ws_.next_layer().async_handshake(ssl::stream_base::client, std::bind(&WebSocketClient::onSslHandshake, shared_from_this(), std::placeholders::_1)); } else { std::cerr << "Connection error: " << ec.message() << std::endl; } } void onSslHandshake(const boost::system::error_code& ec) { if (!ec) { // SSL握手成功后,再发起WebSocket异步握手 ws_.async_handshake(host_, target_, "/", std::bind(&WebSocketClient::onHandshake, shared_from_this(), std::placeholders::_1)); } else { std::cerr << "SSL handshake error: " << ec.message() << std::endl; } } void onHandshake(const boost::system::error_code& ec) { if (!ec) { // WebSocket连接成功,开始发送/接收数据 std::cout << "WebSocket handshake successful" << std::endl; } else { std::cerr << "WebSocket handshake error: " << ec.message() << std::endl; } }
额外注意事项
- 确保
ws_的初始化是正确的:如果ws_是类成员,建议在构造函数中直接初始化,而不是在onConnect中赋值,避免默认构造的空流带来的潜在问题。 - 始终检查异步操作返回的
error_code,及时处理错误情况,避免资源泄漏或连接异常。
内容的提问来源于stack exchange,提问作者SpeakX
相关产品推荐
相关产品推荐

