【问题标题】:Boost-beast websocket handshake problemsBoost-beast websocket 握手问题
【发布时间】:2019-04-28 01:21:24
【问题描述】:

我正在尝试与远程服务器建立 websocket 连接并收到以下错误: WebSocket 握手被远程对等方拒绝

我正在关注这个例子:https://www.boost.org/doc/libs/1_70_0/libs/beast/example/websocket/client/sync/websocket_client_sync.cpp

对于以下服务器:https://api.hitbtc.com/#socket-api-reference

提前感谢您的帮助!

int main(int argc, char** argv) {
    try
    {
        auto const host = "api.hitbtc.com";
        auto const port = "443";

        net::io_context ioc;
        tcp::resolver resolver{ ioc };
        websocket::stream<tcp::socket> ws{ ioc };

        auto const results = resolver.resolve(host, port);

        net::connect(ws.next_layer(), results.begin(), results.end());

        // Perform the websocket handshake - this is where i presume the issue is.
        ws.handshake(host, "/api/2/ws");

        beast::flat_buffer buffer;
        ws.read(buffer);
        ws.close(websocket::close_code::normal);
        std::cout << beast::make_printable(buffer.data()) << std::endl;
    }
    catch (std::exception const& e)
    {
        std::cerr << "Error: " << e.what() << std::endl;
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}

【问题讨论】:

    标签: c++ boost boost-beast beast-websockets


    【解决方案1】:

    您必须提供 ssl 上下文。 这是来自 boost.org 的example

    这里是 api.hitbtc 握手和通过 JSON-RPC 获取货币信息的示例(我省略了证书加载):

    #include <boost/beast/core.hpp>
    #include <boost/beast/ssl.hpp>
    #include <boost/beast/websocket.hpp>
    #include <boost/beast/websocket/ssl.hpp>
    #include <boost/asio/connect.hpp>
    #include <boost/asio/ip/tcp.hpp>
    #include <boost/asio/ssl/stream.hpp>
    #include <cstdlib>
    #include <iostream>
    #include <string>
    
    namespace beast = boost::beast;         // from <boost/beast.hpp>
    namespace http = beast::http;           // from <boost/beast/http.hpp>
    namespace websocket = beast::websocket; // from <boost/beast/websocket.hpp>
    namespace net = boost::asio;            // from <boost/asio.hpp>
    namespace ssl = boost::asio::ssl;       // from <boost/asio/ssl.hpp>
    using tcp = boost::asio::ip::tcp;       // from <boost/asio/ip/tcp.hpp>
    
    // Sends a WebSocket message and prints the response
    int main(int argc, char** argv)
    {
        try
        {
            // Check command line arguments.
            auto const host = "api.hitbtc.com";
            auto const port = "443";
            auto const rpcJson = R"({"method":"getCurrency", "params":{"currency":"ETH"},"id":0})";
    
            // The io_context is required for all I/O
            net::io_context ioc;
    
            // The SSL context is required, and holds certificates
            ssl::context ctx{ssl::context::tlsv12_client};
    
            // This holds the root certificate used for verification
            //load_root_certificates(ctx);
    
            // These objects perform our I/O
            tcp::resolver resolver{ioc};
            websocket::stream<beast::ssl_stream<tcp::socket>> ws{ioc, ctx};
    
            // Look up the domain name
            auto const results = resolver.resolve(host, port);
    
            // Make the connection on the IP address we get from a lookup
            net::connect(ws.next_layer().next_layer(), results.begin(), results.end());
    
            // Perform the SSL handshake
            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");
                }));
    
            // Perform the websocket handshake
            ws.handshake(host, "/api/2/ws");
    
            // Our message in this case should be stringified JSON-RPC request
            ws.write(net::buffer(std::string(rpcJson)));
    
            // This buffer will hold the incoming message
            beast::flat_buffer buffer;
    
            // Read a message into our buffer
            ws.read(buffer);
    
            // Close the WebSocket connection
            ws.close(websocket::close_code::normal);
    
            // If we get here then the connection is closed gracefully
    
            // The make_printable() function helps print a ConstBufferSequence
            std::cout << beast::make_printable(buffer.data()) << std::endl;
        }
        catch(std::exception const& e)
        {
            std::cerr << "Error: " << e.what() << std::endl;
            return EXIT_FAILURE;
        }
        return EXIT_SUCCESS;
    }
    

    你应该得到字符串化的 JSON-RPC 响应。在这种情况下,对于 getCurrency("ETH") 请求,响应将是:

    {"jsonrpc":"2.0","result":{"id":"ETH","fullName":"Ethereum","crypto":true,"payinEnabled":true,"payinPaymentId":false,"payinConfirmations":2,"payoutEnabled":true,"payoutIsPaymentId":false,"transferEnabled":true,"delisted":false,"payoutFee":"0.0428"},"id":null}
    

    【讨论】:

    • 嗨 StPiere,证书加载在这里到底做了什么?您省略了这一行 - //load_root_certificates(ctx); .我不太明白这个 load_root_certificates 是做什么的?如果我们不加载证书,该示例如何工作?
    • @eternal:此示例用于展示如何仅使用 boost 设置 ssl 上下文 - 加载证书超出了范围。这是来自 boost docs(非生产性)的 load_certificates 的 example
    • 谢谢。关于您的示例的另一个问题是这一行 - ssl::context ctx{ssl::context::tlsv12_client}。当我尝试使用相同的 tlsv12_client 时,我的应用程序在握手期间崩溃。如果我使用 ssl::context::sslv23 它不会崩溃,但会给我一个错误 - “握手:tlsv1 警报协议版本”。对此有什么想法吗?
    猜你喜欢
    • 2018-11-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-06
    • 2018-11-28
    • 1970-01-01
    相关资源
    最近更新 更多