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

使用Boost Beast实现WebSocket客户端时遇编译错误求助

Boost Beast WebSocket SSL流编译错误排查

问题描述

使用Boost Beast实现C++ WebSocket客户端,连接加密货币交易所WebSocket API处理行情数据时,遇到与Boost Beast和Boost Asio SSL流相关的编译错误,错误触发点在async_teardown逻辑中。

代码片段

#include <array>
#include <atomic>
#include <thread>
#include <cstdlib>
#include <string>
#include <thread>
#include <iostream>
#include <sstream>
#include <curl/curl.h>
#include <shared_mutex>
#include <openssl/sha.h>
#include <openssl/hmac.h>
#include <nlohmann/json.hpp>

#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/beast.hpp>

// ... [Other parts of the code like the OrderBook class]

class WebSocketClient
{
private:
    using Socket = tcp::socket;
    using Stream = ssl::stream<Socket>;
    using WS = websocket::stream<Stream>;

    net::io_context ioc_;
    OrderBook &orderBook_;
    std::string coin_;
    tcp::resolver resolver_{ioc_};
    ssl::context ssl_context_{ssl::context::tlsv12_client};
    WS ws_{ioc_, ssl_context_};
    boost::beast::flat_buffer buffer_;

public:
    WebSocketClient(OrderBook &orderBook, std::string coin) : orderBook_(orderBook), coin_(std::move(coin))
    {
        ssl_context_.set_default_verify_paths();
        ws_.next_layer().set_verify_mode(ssl::verify_peer);
        ws_.next_layer().set_verify_callback(ssl::rfc2818_verification("stream.binance.com"));
    }

    void read()
    {
        ws_.async_read(
            buffer_,
            [this](boost::system::error_code ec, std::size_t bytes_transferred)
            {
                onRead(ec, bytes_transferred);
            });
    }

    void send(std::string msg)
    {
        ws_.write(net::buffer(msg));
    }

    void connectAndSubscribe()
    {
        // Resolve the host name and connect to the server
        auto results = resolver_.resolve("stream.binance.com", "9443");
        auto ep = connect(ws_.next_layer().next_layer(), results);
        auto host_ = "stream.binance.com:" + std::to_string(ep.port());

        ws_.next_layer().handshake(Stream::client);
        // Set a decorator to change the User-Agent of the handshake
        ws_.set_option(websocket::stream_base::decorator([](websocket::request_type &req)
                                                         { req.set(http::field::user_agent, std::string(BOOST_BEAST_VERSION_STRING) + " websocket-client"); }));

        std::string path = "/ws/" + coin_ + "@depth5@100ms";
        ws_.handshake(host_, path);
        std::cout << "Handshake successful." << std::endl;

        json j_msg = {
            {"method", "SUBSCRIBE"},
            {"params", {coin_ + "@depth5@100ms"}},
            {"id", 1}};

        std::string msg = j_msg.dump(); // Serialize JSON to string
        send(msg);
        std::cout << "Subscription request done!" << std::endl;
        read();
    }

    void onRead(boost::system::error_code ec, std::size_t bytes_transferred)
    {
        if (ec)
        {
            std::cerr << "Read error: " << ec.message() << std::endl;
            return;
        }

        // Process the received message
        std::string message = boost::beast::buffers_to_string(buffer_.data());
        buffer_.consume(bytes_transferred);

        try
        {
            json j = json::parse(message);
            // Process JSON message and update OrderBook
            std::cout << "Reading request done!" << std::endl;
            processMessage(j);
        }
        catch (const json::exception &e)
        {
            std::cerr << "JSON parsing error: " << e.what() << std::endl;
        }

        // Continue reading messages
        read();
    }

    void processMessage(const json &j)
    {
        if (j.contains("lastUpdateId") && j.contains("bids") && j.contains("asks"))
        {
            int index = 0;
            for (const auto &bid : j["bids"])
            {
                float price = stof(bid[0].get<string>());
                float quantity = stof(bid[1].get<string>());

                orderBook_.update(index++, price);
                orderBook_.update(index++, quantity);
            }
            index = 10; // Start index for asks

            for (const auto &ask : j["asks"])
            {
                float price = stof(ask[0].get<string>());
                float quantity = stof(ask[1].get<string>());

                orderBook_.update(index++, price);
                orderBook_.update(index++, quantity);
            }
        }
    }

};

错误信息

/usr/local/include/boost/beast/websocket/teardown.hpp:105:5: error: static assertion failed due to requirement 'sizeof(boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::any_io_executor>>) == -1': Unknown Socket type in async_teardown.

构建环境

  • 构建系统:CMake + Ninja
  • 已尝试升级Boost和OpenSSL至最新版本,问题仍存在。

解决思路

1. 显式包含WebSocket SSL支持头文件

编译错误的核心原因是Boost Beast未找到针对SSL流的async_teardown特化实现。需要在代码中显式包含:

#include <boost/beast/websocket/ssl.hpp>

这个头文件提供了SSL流与WebSocket集成所需的teardown逻辑,仅包含<boost/beast.hpp>无法自动引入该特化。

2. 检查命名空间一致性

确保所有Boost Asio/Beast相关类型使用统一的命名空间:

  • 若使用别名namespace net = boost::asio,则所有tcp::socket、ssl::stream等类型需来自net命名空间,修正类型别名定义:
    using Socket = net::ip::tcp::socket;
    using Stream = net::ssl::stream<Socket>;
    using WS = boost::beast::websocket::stream<Stream>;
    
    避免因命名空间混乱导致模板特化匹配失败。

3. 修正WebSocket握手的Host字段

虽然这不是编译错误,但会导致运行时握手失败:当前代码中host_拼接了端口号,WebSocket握手的Host字段仅需主机名(如"stream.binance.com"),无需附加端口,修改为:

auto host_ = "stream.binance.com";

4. 验证Boost版本兼容性

确保使用的Boost版本完全兼容:Beast库对SSL流的支持在Boost 1.70及以上版本才稳定,若升级后仍有问题,可尝试指定Boost版本为1.74+(币安官方示例常用版本)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 17:57:04