C++ 项目中 Boost Beast Websocket 编译错误

问题描述 投票:0回答:1

我正在开发一个 C++ 项目,其中使用 Boost Beast 来实现 WebSocket 客户端。该项目旨在连接到加密货币交易所的 WebSocket API 并处理市场数据。但是,我遇到了与带有 SSL 流的 Boost Beast 和 Boost Asio 相关的编译错误。下面是代码的相关部分和我收到的错误消息。

代码:

#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:错误:由于要求 'sizeof(boost::asio::ssl::stream>) == -1,静态断言失败': async_teardown 中未知的套接字类型。

编译命令: 我使用 CMake 和 Ninja 作为构建系统。我已经尝试将 Boost 和 OpenSSL 更新到最新版本,但问题仍然存在。任何有关可能导致此编译错误的原因以及如何解决该错误的见解将不胜感激。

c++ websocket boost boost-asio teardown
1个回答
0
投票

错误源自这里:

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

100%是因为你忘了包含

#include <boost/beast/ssl.hpp>

这甚至没有计算问题中遗漏的内容:

namespace net       = boost::asio;
namespace ssl       = net::ssl;
namespace http      = boost::beast::http;
namespace websocket = boost::beast::websocket;
using net::ip::tcp;
using json = nlohmann::json;

struct OrderBook {
    void update(int, float) {}
};

幸运的是,还有一堆多余/未使用的包括:

// #include <array>
// #include <cstdlib>
// #include <curl/curl.h>
// #include <sstream>
// #include <string>

这里是你的代码,再次变得独立:

实时编译器资源管理器

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

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

namespace net       = boost::asio;
namespace ssl       = net::ssl;
namespace http      = boost::beast::http;
namespace websocket = boost::beast::websocket;
using net::ip::tcp;
using json = nlohmann::json;

struct OrderBook {
    void update(int, float) {}
};

class WebSocketClient {
  private:
    using error_code = boost::beast::error_code;
    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 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;
        readLoop();
    }

  private:
    void readLoop() {
        ws_.async_read(buffer_, [this](error_code ec, size_t n) { onRead(std::move(ec), n); });
    }

    void onRead(error_code ec, 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 (json::exception const& e) {
            std::cerr << "JSON parsing error: " << e.what() << std::endl;
        }

        // Continue reading messages
        readLoop();
    }

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

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

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

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

int main() {
    //
}
© www.soinside.com 2019 - 2024. All rights reserved.