c++ - Boost-WebSocket 握手被远程对等点拒绝

标签 c++ boost websocket beast

我正在尝试连接到 Kraken websocket API。但我收到“WebSocket 握手被远程对等点拒绝”错误。

我为交易所的websocket和rest api客户端编写了一个包装类。它与Binance websocket API配合良好,但Kraken websocket连接不成功。

我也尝试了不同类型的 tls(ssl::context ctx_webSocket{ ssl::context::tlsv13_client };) 版本,但结果是相同的。

    class Exchange {
public:
    Exchange(std::string name, const std::string& http_host) :m_name(std::move(name)) {
        init_http(http_host);
    }


    void init_http(std::string const& host) {

        const auto results{ resolver.resolve(host,"443") };
        get_lowest_layer(stream).connect(results);
        if (!SSL_set_tlsext_host_name(stream.native_handle(), host.c_str()))
        {
            boost::system::error_code ec{ static_cast<int>(::ERR_get_error()), boost::asio::error::get_ssl_category() };
            throw boost::system::system_error{ ec };
        }
        stream.handshake(ssl::stream_base::client);
    }

    void init_webSocket(std::string const& host, std::string const& port, std::string const& target) {
        auto const results = resolver_webSocket.resolve(host, port);
        net::connect(ws.next_layer().next_layer(), results.begin(), results.end());
        ws.next_layer().handshake(ssl::stream_base::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-coro");
        }));
        ws.handshake(host, target.c_str());
    }

    void read_Socket() {
        ws.read(buffer);

    }
    void write_Socket(const std::string& text) {
        ws.write(net::buffer(text));
    }

    std::string get_socket_data() {
        return beast::buffers_to_string(buffer.data());
    }
    void buffer_clear() {
        buffer.clear();

    }
    void webSocket_close() {
        ws.close(websocket::close_code::none);
    }
private:
    // HTTP REQUEST SET //
    std::string m_name;
    net::io_context ioc;
    ssl::context ctx{ ssl::context::tlsv12_client };
    tcp::resolver resolver{ ioc };
    Stream stream{ ioc, ctx };

    // WEB SOCKET SET //
    std::string m_web_socket_host;
    std::string m_web_socket_port;
    beast::flat_buffer buffer;
    net::io_context ioc_webSocket;
    ssl::context ctx_webSocket{ ssl::context::tlsv13_client };
    tcp::resolver resolver_webSocket{ ioc_webSocket };
    websocket::stream<beast::ssl_stream<tcp::socket>> ws{ ioc_webSocket, ctx_webSocket };

};

int main()
{
    Exchange kraken{ "kraken","api.kraken.com" };

    try
    {

        kraken.init_webSocket("ws.kraken.com", "443", "/");

        while (true)
        {
            kraken.read_Socket();
            std::cout << kraken.get_socket_data();

            return 1;


            kraken.buffer_clear();
        }
        kraken.webSocket_close();
    }


    catch (std::exception const& e)
    {
        std::cerr << "Error: " << e.what() << std::endl;
    }

}

最佳答案

已解决。我已经发现问题出在哪里了。在websocket握手之前,必须设置SNI主机名,下面是工作测试代码。

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

namespace net       = boost::asio;
namespace ssl       = net::ssl;
namespace beast     = boost::beast;
namespace http      = beast::http;
namespace websocket = beast::websocket;

using tcp      = net::ip::tcp;
using Request  = http::request<http::string_body>;
using Stream   = beast::ssl_stream<beast::tcp_stream>;
using Response = http::response<http::dynamic_body>;

class Exchange {
  public:
    Exchange(std::string name, const std::string& http_host)
        : m_name(std::move(name))
    {
        init_http(http_host);
    }

    void init_http(std::string const& host)
    {
        const auto results{resolver.resolve(host, "443")};
        get_lowest_layer(stream).connect(results);
        // Set SNI Hostname (many hosts need this to handshake successfully)
        if (!SSL_set_tlsext_host_name(stream.native_handle(), host.c_str())) {
            boost::system::error_code ec{
                static_cast<int>(::ERR_get_error()),
                boost::asio::error::get_ssl_category()};
            throw boost::system::system_error{ec};
        }
        stream.handshake(ssl::stream_base::client);
    }

    void init_webSocket(std::string const& host, std::string const& port,
                        const char* p = "")
    {
        // Set SNI Hostname (many hosts need this to handshake successfully)
        if (!SSL_set_tlsext_host_name(ws.next_layer().native_handle(),
                                      host.c_str()))
            throw beast::system_error(
                beast::error_code(static_cast<int>(::ERR_get_error()),
                                  net::error::get_ssl_category()),
                "Failed to set SNI Hostname");
        auto const results = resolver_webSocket.resolve(host, port);
        net::connect(ws.next_layer().next_layer(), results.begin(),
                     results.end());
        ws.next_layer().handshake(ssl::stream_base::client);

        ws.handshake(host, p);
    }

    void read_Socket() { ws.read(buffer); }

    bool is_socket_open()
    {
        if (ws.is_open())
            return true;
        return false;
    }

    void write_Socket(const std::string& text) { ws.write(net::buffer(text)); }

    std::string get_socket_data()
    {
        return beast::buffers_to_string(buffer.data());
    }
    void buffer_clear() { buffer.clear(); }

    void webSocket_close() { ws.close(websocket::close_code::none); }

  private:
    // HTTP REQUEST SET //
    std::string     m_name;
    net::io_context ioc;
    ssl::context    ctx{ssl::context::tlsv12_client};
    tcp::resolver   resolver{ioc};
    Stream          stream{ioc, ctx};

    // WEB SOCKET SET //
    std::string        m_web_socket_host;
    std::string        m_web_socket_port;
    beast::flat_buffer buffer;
    net::io_context    ioc_webSocket;
    ssl::context       ctx_webSocket{ssl::context::tlsv12_client};
    tcp::resolver      resolver_webSocket{ioc_webSocket};
    websocket::stream<beast::ssl_stream<tcp::socket>> ws{ioc_webSocket,
                                                         ctx_webSocket};
};

int main()
{
    Exchange kraken{"kraken", "ws.kraken.com"};

    try {
        kraken.init_webSocket("ws.kraken.com", "443", "/");
        if (kraken.is_socket_open())
            kraken.write_Socket(
                R"({"event": "subscribe","pair": ["MINA/USD"],"subscription": {"name": "spread"}})");
        while (true) {
            kraken.read_Socket();
            std::cout << kraken.get_socket_data();

            kraken.buffer_clear();
        }
        kraken.webSocket_close();
    } catch (std::exception const& e) {
        std::cerr << "Error: " << e.what() << std::endl;
        return 1;
    }
}

关于c++ - Boost-WebSocket 握手被远程对等点拒绝,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69458228/

相关文章:

c++ - 是否可以在 ARC 中使用 native C++ 代码?

c++ - C++中的命名空间冲突

rest - Suave with f# - 如何在 f# 聊天应用程序中使用 rest api 和 websocket 端口?

c++ - N体算法 : why is this slower in parallel?

c++ - 返回 shared_ptr 时如何实现协变返回类型?

C++ 应用程序 - 我应该为库使用静态链接还是动态链接?

unit-testing - Boost 单元测试框架报告的 "mks"单元是什么?

java - Tomcat 上的 Websockets : how to shutdown the server cleanly?

javascript - node.js socket.io 服务器延迟较长

c++ - 在 Linux 中正确部署 Qt 应用程序