我无法构建 beast websocket 示例中提供的示例之一

i cannot build one of the examples provided in the beast websocket example

我的代码:

#include <boost/beast/core.hpp>
#include <boost/beast/websocket.hpp>
#include <boost/asio/strand.hpp>
#include <boost/thread/thread.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <cstdlib>
#include <fstream>
#include <jsoncpp/json/value.h>
#include <jsoncpp/json/json.h>
#include <functional>
#include <iostream>
#include <memory>
#include <string>
#include<unistd.h>
#include<sys/types.h>
using namespace std;

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>
using tcp = boost::asio::ip::tcp;       // from <boost/asio/ip/tcp.hpp>


//------------------------------------------------------------------------------

// Report a failure
void
fail(beast::error_code ec, char const* what)
{
    std::cerr << what << ": " << ec.message() << "\n";
}

// Sends a WebSocket message and prints the response
class session : public std::enable_shared_from_this<session>
{
    tcp::resolver resolver_;
    websocket::stream<beast::tcp_stream> ws_;
    beast::flat_buffer buffer_;
    std::string host_;
    Json::Value json;

public:
    // Resolver and socket require an io_context
    explicit
    session(net::io_context& ioc)
        : resolver_(net::make_strand(ioc))
        , ws_(net::make_strand(ioc))
    {
    }

    // Start the asynchronous operation
    void
    run(
        char const* host,
        char const* port,
        Json::Value text)
    {
        // Save these for later
        host_ = host;
        json = text;

        // Look up the domain name
        resolver_.async_resolve(
            host,
            port,
            beast::bind_front_handler(
                &session::on_resolve,
                shared_from_this()));
    }

    void
    on_resolve(
        beast::error_code ec,
        tcp::resolver::results_type results)
    {
        if(ec)
            return fail(ec, "resolve");

        // Set the timeout for the operation
        beast::get_lowest_layer(ws_).expires_after(std::chrono::seconds(30));

        // Make the connection on the IP address we get from a lookup
        beast::get_lowest_layer(ws_).async_connect(
            results,
            beast::bind_front_handler(
                &session::on_connect,
                shared_from_this()));
    }

    void
    on_connect(beast::error_code ec, tcp::resolver::results_type::endpoint_type ep)
    {
        if(ec)
            return fail(ec, "connect");

        // Turn off the timeout on the tcp_stream, because
        // the websocket stream has its own timeout system.
        beast::get_lowest_layer(ws_).expires_never();

        // Set suggested timeout settings for the websocket
        ws_.set_option(
            websocket::stream_base::timeout::suggested(
                beast::role_type::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-async");
            }));

        // Update the host_ string. This will provide the value of the
        // Host HTTP header during the WebSocket handshake.
        // See https://tools.ietf.org/html/rfc7230#section-5.4
        host_ += ':' + std::to_string(ep.port());

        // Perform the websocket handshake
        ws_.async_handshake(host_, "/",
            beast::bind_front_handler(
                &session::on_handshake,
                shared_from_this()));
    }

    std::string 
    Json_to_string(const Json::Value &json)
    {
        std::string result;
        Json::StreamWriterBuilder wbuilder;

        wbuilder["indentation"] = "";       // Optional
        result = Json::writeString(wbuilder, json);
        return result;
    }

    void
    on_handshake(beast::error_code ec)
    {
        if(ec)
            return fail(ec, "handshake");
        
        // Send the message
        std::string jsonner = Json_to_string(json);
        auto jsontxt = std::make_shared<std::string>(jsonner);

        ws_.async_write(
            boost::asio::buffer(*jsontxt),
            beast::bind_front_handler(
                &session::on_write,
                shared_from_this(),jsontxt));
    }

    void
    on_write(
        beast::error_code ec,
        std::size_t bytes_transferred)
    {
        boost::ignore_unused(bytes_transferred);

        if(ec)
            return fail(ec, "write");
        
        // Read a message into our buffer
        ws_.async_read(
            buffer_,
            beast::bind_front_handler(
                &session::on_read,
                shared_from_this()));
    }

    void
    on_read(
        beast::error_code ec,
        std::size_t bytes_transferred)
    {
        boost::ignore_unused(bytes_transferred);

        if(ec)
            return fail(ec, "read");

        // Close the WebSocket connection
        ws_.async_close(websocket::close_code::normal,
            beast::bind_front_handler(
                &session::on_close,
                shared_from_this()));
    }

    void
    on_close(beast::error_code ec)
    {
        if(ec)
            return fail(ec, "close");

        // 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;
    }
};

//------------------------------------------------------------------------------

int main(int argc, char** argv)
{
    // Check command line arguments.
    if(argc != 4)
    {
        std::cerr <<
            "Usage: websocket-client-async <host> <port> <text>\n" <<
            "Example:\n" <<
            "    websocket-client-async echo.websocket.org 80 \"Hello, world!\"\n";
        return EXIT_FAILURE;
    }
    // auto const host = argv[1];
    // auto const port = argv[1];
    // auto const text = argv[1];

    ifstream file("details.json");
    Json::Value actualjson;
    Json::Reader jsonreader;

    jsonreader.parse(file,actualjson);

    // The io_context is required for all I/O
    net::io_context context;

    // Launch the asynchronous operation
    std::make_shared<session>(context)->run("stream.binance.com","9443", actualjson);

    // Run the I/O service. The call will return when
    // the socket is closed.
    context.run();

    return EXIT_SUCCESS;
}

完整错误in a gist,缩写:

In file included from /usr/include/boost/beast/core/bind_handler.hpp:14,
                 from /usr/include/boost/beast/core/async_base.hpp:14,
                 from /usr/include/boost/beast/core.hpp:15,
                 from /home/user/Desktop/HFTBOT/src/main.cpp:1:
/usr/include/boost/beast/core/detail/bind_handler.hpp: In instantiation of ‘void boost::beast::...
/usr/include/boost/beast/core/detail/bind_handler.hpp:258:9:   required from ‘void boost::beast...
/usr/include/boost/beast/core/async_base.hpp:353:13:   required from ‘void boost::beast::async_...
/usr/include/boost/beast/websocket/impl/write.hpp:167:59:   required from ‘void boost::beast::w...
/usr/include/boost/beast/websocket/impl/write.hpp:140:16:   required from ‘boost::beast::websoc...
/usr/include/boost/beast/websocket/impl/write.hpp:459:9:   required from ‘void boost::beast::we...
/usr/include/boost/asio/async_result.hpp:82:49:   required from ‘static boost::asio::async_resu...
/usr/include/boost/asio/async_result.hpp:257:25:   required from ‘typename std::enable_if<boost...
/usr/include/boost/beast/websocket/impl/write.hpp:772:39:   required from ‘typename boost::asio...
/home/user/Desktop/HFTBOT/src/main.cpp:153:44:   required from here
/usr/include/boost/beast/core/detail/bind_handler.hpp:235:24: error: no match for call to ‘(std...
  235 |         std::mem_fn(h_)(
      |         ~~~~~~~~~~~~~~~^
  236 |             detail::get<I>(std::move(args_))...,
      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  237 |             std::forward<Ts>(ts)...);
      |             ~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /usr/include/boost/system/error_code.hpp:19,
                 from /usr/include/boost/beast/core/error.hpp:14,
                 from /usr/include/boost/beast/core/detail/bind_handler.hpp:13,
                 from /usr/include/boost/beast/core/bind_handler.hpp:14,
                 from /usr/include/boost/beast/core/async_base.hpp:14,
                 from /usr/include/boost/beast/core.hpp:15,
                 from /home/user/Desktop/HFTBOT/src/main.cpp:1:
/usr/include/c++/9/functional:110:2: note: candidate: ‘template<class ... _Args> decltype (std:...
  110 |  operator()(_Args&&... __args) const
      |  ^~~~~~~~
/usr/include/c++/9/functional:110:2: note:   template argument deduction/substitution failed:
/usr/include/c++/9/functional: In substitution of ‘template<class ... _Args> decltype (std::__i...
/usr/include/boost/beast/core/detail/bind_handler.hpp:235:24:   required from ‘void boost::beas...
/usr/include/boost/beast/core/detail/bind_handler.hpp:258:9:   required from ‘void boost::beast...
/usr/include/boost/beast/core/async_base.hpp:353:13:   required from ‘void boost::beast::async_...
/usr/include/boost/beast/websocket/impl/write.hpp:167:59:   required from ‘void boost::beast::w...
/usr/include/boost/beast/websocket/impl/write.hpp:140:16:   required from ‘boost::beast::websoc...
/usr/include/boost/beast/websocket/impl/write.hpp:459:9:   required from ‘void boost::beast::we...
/usr/include/boost/asio/async_result.hpp:82:49:   required from ‘static boost::asio::async_resu...
/usr/include/boost/asio/async_result.hpp:257:25:   required from ‘typename std::enable_if<boost...
/usr/include/boost/beast/websocket/impl/write.hpp:772:39:   required from ‘typename boost::asio...
/home/user/Desktop/HFTBOT/src/main.cpp:153:44:   required from here
/usr/include/c++/9/functional:113:27: error: no matching function for call to ‘__invoke(void (s...
  113 |  -> decltype(std::__invoke(_M_pmf, std::forward<_Args>(__args)...))
      |              ~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /usr/include/c++/9/tuple:41,
                 from /usr/include/c++/9/functional:54,
                 from /usr/include/boost/system/error_code.hpp:19,
                 from /usr/include/boost/beast/core/error.hpp:14,
                 from /usr/include/boost/beast/core/detail/bind_handler.hpp:13,
                 from /usr/include/boost/beast/core/bind_handler.hpp:14,
                 from /usr/include/boost/beast/core/async_base.hpp:14,
                 from /usr/include/boost/beast/core.hpp:15,
                 from /home/user/Desktop/HFTBOT/src/main.cpp:1:
/usr/include/c++/9/bits/invoke.h:89:5: note: candidate: ‘template<class _Callable, class ... _A...
   89 |     __invoke(_Callable&& __fn, _Args&&... __args)
      |     ^~~~~~~~
/usr/include/c++/9/bits/invoke.h:89:5: note:   template argument deduction/substitution failed:...
/usr/include/c++/9/bits/invoke.h: In substitution of ‘template<class _Callable, class ... _Args...
/usr/include/c++/9/functional:113:27:   required by substitution of ‘template<class ... _Args> ...
/usr/include/boost/beast/core/detail/bind_handler.hpp:235:24:   required from ‘void boost::beas...
/usr/include/boost/beast/core/detail/bind_handler.hpp:258:9:   required from ‘void boost::beast...
/usr/include/boost/beast/core/async_base.hpp:353:13:   required from ‘void boost::beast::async_...
/usr/include/boost/beast/websocket/impl/write.hpp:167:59:   required from ‘void boost::beast::w...
/usr/include/boost/beast/websocket/impl/write.hpp:140:16:   required from ‘boost::beast::websoc...
/usr/include/boost/beast/websocket/impl/write.hpp:459:9:   required from ‘void boost::beast::we...
/usr/include/boost/asio/async_result.hpp:82:49:   required from ‘static boost::asio::async_resu...
/usr/include/boost/asio/async_result.hpp:257:25:   required from ‘typename std::enable_if<boost...
/usr/include/boost/beast/websocket/impl/write.hpp:772:39:   required from ‘typename boost::asio...
/home/user/Desktop/HFTBOT/src/main.cpp:153:44:   required from here
/usr/include/c++/9/bits/invoke.h:89:5: error: no type named ‘type’ in ‘struct std::__invoke_res...
In file included from /usr/include/boost/beast/core/bind_handler.hpp:14,
                 from /usr/include/boost/beast/core/async_base.hpp:14,
                 from /usr/include/boost/beast/core.hpp:15,
                 from /home/user/Desktop/HFTBOT/src/main.cpp:1:
/usr/include/boost/beast/core/detail/bind_handler.hpp: In instantiation of ‘void boost::beast::...
/usr/include/boost/beast/core/detail/bind_handler.hpp:258:9:   required from ‘void boost::beast...
/usr/include/boost/beast/core/detail/bind_handler.hpp:224:9:   required from ‘void boost::beast...
/usr/include/boost/beast/core/detail/bind_handler.hpp:258:9:   required from ‘void boost::beast...
/usr/include/boost/asio/bind_executor.hpp:414:61:   required from ‘typename std::result_of<T(Ar...
/usr/include/boost/asio/detail/executor_function.hpp:91:15:   required from ‘static void boost:...
/usr/include/boost/asio/detail/executor_function.hpp:66:50:   [ skipping 8 instantiation contex...
/usr/include/boost/beast/websocket/impl/write.hpp:140:16:   required from ‘boost::beast::websoc...
/usr/include/boost/beast/websocket/impl/write.hpp:459:9:   required from ‘void boost::beast::we...
/usr/include/boost/asio/async_result.hpp:82:49:   required from ‘static boost::asio::async_resu...
/usr/include/boost/asio/async_result.hpp:257:25:   required from ‘typename std::enable_if<boost...
/usr/include/boost/beast/websocket/impl/write.hpp:772:39:   required from ‘typename boost::asio...
/home/user/Desktop/HFTBOT/src/main.cpp:153:44:   required from here
/usr/include/boost/beast/core/detail/bind_handler.hpp:235:24: error: no match for call to ‘(std...
  235 |         std::mem_fn(h_)(
      |         ~~~~~~~~~~~~~~~^
  236 |             detail::get<I>(std::move(args_))...,
      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  237 |             std::forward<Ts>(ts)...);
      |             ~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /usr/include/boost/system/error_code.hpp:19,
                 from /usr/include/boost/beast/core/error.hpp:14,
                 from /usr/include/boost/beast/core/detail/bind_handler.hpp:13,
                 from /usr/include/boost/beast/core/bind_handler.hpp:14,
                 from /usr/include/boost/beast/core/async_base.hpp:14,
                 from /usr/include/boost/beast/core.hpp:15,
                 from /home/user/Desktop/HFTBOT/src/main.cpp:1:
/usr/include/c++/9/functional:110:2: note: candidate: ‘template<class ... _Args> decltype (std:...
  110 |  operator()(_Args&&... __args) const
      |  ^~~~~~~~
/usr/include/c++/9/functional:110:2: note:   template argument deduction/substitution failed:
/usr/include/c++/9/functional: In substitution of ‘template<class ... _Args> decltype (std::__i...
/usr/include/boost/beast/core/detail/bind_handler.hpp:235:24:   required from ‘void boost::beas...
/usr/include/boost/beast/core/detail/bind_handler.hpp:258:9:   required from ‘void boost::beast...
/usr/include/boost/beast/core/detail/bind_handler.hpp:224:9:   required from ‘void boost::beast...
/usr/include/boost/beast/core/detail/bind_handler.hpp:258:9:   required from ‘void boost::beast...
/usr/include/boost/asio/bind_executor.hpp:414:61:   required from ‘typename std::result_of<T(Ar...
/usr/include/boost/asio/detail/executor_function.hpp:91:15:   [ skipping 9 instantiation contex...
/usr/include/boost/beast/websocket/impl/write.hpp:140:16:   required from ‘boost::beast::websoc...
/usr/include/boost/beast/websocket/impl/write.hpp:459:9:   required from ‘void boost::beast::we...
/usr/include/boost/asio/async_result.hpp:82:49:   required from ‘static boost::asio::async_resu...
/usr/include/boost/asio/async_result.hpp:257:25:   required from ‘typename std::enable_if<boost...
/usr/include/boost/beast/websocket/impl/write.hpp:772:39:   required from ‘typename boost::asio...
/home/user/Desktop/HFTBOT/src/main.cpp:153:44:   required from here
/usr/include/c++/9/functional:113:27: error: no matching function for call to ‘__invoke(void (s...
  113 |  -> decltype(std::__invoke(_M_pmf, std::forward<_Args>(__args)...))
      |              ~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /usr/include/c++/9/tuple:41,
                 from /usr/include/c++/9/functional:54,
                 from /usr/include/boost/system/error_code.hpp:19,
                 from /usr/include/boost/beast/core/error.hpp:14,
                 from /usr/include/boost/beast/core/detail/bind_handler.hpp:13,
                 from /usr/include/boost/beast/core/bind_handler.hpp:14,
                 from /usr/include/boost/beast/core/async_base.hpp:14,
                 from /usr/include/boost/beast/core.hpp:15,
                 from /home/user/Desktop/HFTBOT/src/main.cpp:1:
/usr/include/c++/9/bits/invoke.h:89:5: note: candidate: ‘template<class _Callable, class ... _A...
   89 |     __invoke(_Callable&& __fn, _Args&&... __args)
      |     ^~~~~~~~
/usr/include/c++/9/bits/invoke.h:89:5: note:   template argument deduction/substitution failed:...
/usr/include/c++/9/bits/invoke.h: In substitution of ‘template<class _Callable, class ... _Args...
/usr/include/c++/9/functional:113:27:   required by substitution of ‘template<class ... _Args> ...
/usr/include/boost/beast/core/detail/bind_handler.hpp:235:24:   required from ‘void boost::beas...
/usr/include/boost/beast/core/detail/bind_handler.hpp:258:9:   required from ‘void boost::beast...
/usr/include/boost/beast/core/detail/bind_handler.hpp:224:9:   required from ‘void boost::beast...
/usr/include/boost/beast/core/detail/bind_handler.hpp:258:9:   required from ‘void boost::beast...
/usr/include/boost/asio/bind_executor.hpp:414:61:   [ skipping 10 instantiation contexts, use -...
/usr/include/boost/beast/websocket/impl/write.hpp:140:16:   required from ‘boost::beast::websoc...
/usr/include/boost/beast/websocket/impl/write.hpp:459:9:   required from ‘void boost::beast::we...
/usr/include/boost/asio/async_result.hpp:82:49:   required from ‘static boost::asio::async_resu...
/usr/include/boost/asio/async_result.hpp:257:25:   required from ‘typename std::enable_if<boost...
/usr/include/boost/beast/websocket/impl/write.hpp:772:39:   required from ‘typename boost::asio...
/home/user/Desktop/HFTBOT/src/main.cpp:153:44:   required from here
/usr/include/c++/9/bits/invoke.h:89:5: error: no type named ‘type’ in ‘struct std::__invoke_res...
make[2]: *** [CMakeFiles/hftbot.dir/build.make:83: CMakeFiles/hftbot.dir/src/main.cpp.o] Error ...
make[1]: *** [CMakeFiles/Makefile2:116: CMakeFiles/hftbot.dir/all] Error 2

所以我正在尝试向 binance 发送 json 请求,以通过 websocket 流式传输市场更新。 币安 api 文档:https://binance-docs.github.io/apidocs/spot/en/#websocket-market-streams

我的details.json长相:

{
    "method": "SUBSCRIBE",
    "params":
    [
        "btcusdt@depth"
    ],
    "id": 1
}

我不知道这里发生了什么。请帮助我并提前谢谢!

这里:

    auto jsontxt = std::make_shared<std::string>(jsonner);

    ws_.async_write(
        boost::asio::buffer(*jsontxt),
        beast::bind_front_handler(
            &session::on_write,
            shared_from_this(),jsontxt));

您绑定了一个额外的参数jsontxt。这个想法没问题:您想将 json 文本缓冲区的生命周期延长到写入操作的持续时间。但是 on_write 不接受额外的 jsontxt 参数。

您可以修复从

void on_write(beast::error_code ec, std::size_t bytes_transferred) {

void on_write(std::shared_ptr<std::string> /*jsontxt*/,
              beast::error_code ec, std::size_t bytes_transferred) {

确实可以编译。但是,它有点笨拙,扩展性不好(您还要将多少参数绑定到各种处理程序中?)。我们可以做得更好吗?

做得更好

请注意 session class 已经使用共享所有权:

class session : public std::enable_shared_from_this<session>

接下来,请注意您已经使用shared_from_this()(而不是仅this)在处理程序中共享该所有权。

这意味着如果您让 jsontxt 成为 class 的成员,您将 已经 拥有 life-time 保证,但效率更高并且没有使用额外绑定参数的笨拙。

事实上,您可以将字符串化的 JSON 直接存储在 run():

#include <boost/beast/core.hpp>
#include <boost/beast/websocket.hpp>
#include <boost/asio/strand.hpp>
#include <boost/thread/thread.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>

#include <cstdlib>
#include <fstream>
#include <json/json.h>
#include <functional>
#include <iostream>
#include <memory>
#include <string>

#include <sys/types.h>
#include <unistd.h>

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>
using tcp           = boost::asio::ip::tcp; // from <boost/asio/ip/tcp.hpp>

//------------------------------------------------------------------------------

// Report a failure
void
fail(beast::error_code ec, char const* what)
{
    std::cerr << what << ": " << ec.message() << "\n";
}

// Sends a WebSocket message and prints the response
class session : public std::enable_shared_from_this<session>
{
    tcp::resolver                        resolver_;
    websocket::stream<beast::tcp_stream> ws_;

    beast::flat_buffer buffer_;
    std::string        host_;
    std::string        message_text_;

  public:
    // Resolver and socket require an io_context
    explicit
    session(net::io_context& ioc)
        : resolver_(net::make_strand(ioc))
        , ws_(net::make_strand(ioc))
    {
    }

    // Start the asynchronous operation
    void
    run(
        char const* host,
        char const* port,
        Json::Value message)
    {
        // Save these for later
        host_         = host;
        message_text_ = Json_to_string(message);

        // Look up the domain name
        resolver_.async_resolve(
            host,
            port,
            beast::bind_front_handler(
                &session::on_resolve,
                shared_from_this()));
    }

    void
    on_resolve(
        beast::error_code ec,
        tcp::resolver::results_type results)
    {
        if(ec)
            return fail(ec, "resolve");

        // Set the timeout for the operation
        beast::get_lowest_layer(ws_).expires_after(std::chrono::seconds(30));

        // Make the connection on the IP address we get from a lookup
        beast::get_lowest_layer(ws_).async_connect(
            results,
            beast::bind_front_handler(
                &session::on_connect,
                shared_from_this()));
    }

    void
    on_connect(beast::error_code ec, tcp::resolver::results_type::endpoint_type ep)
    {
        if(ec)
            return fail(ec, "connect");

        // Turn off the timeout on the tcp_stream, because
        // the websocket stream has its own timeout system.
        beast::get_lowest_layer(ws_).expires_never();

        // Set suggested timeout settings for the websocket
        ws_.set_option(
            websocket::stream_base::timeout::suggested(
                beast::role_type::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-async");
            }));

        // Update the host_ string. This will provide the value of the
        // Host HTTP header during the WebSocket handshake.
        // See https://tools.ietf.org/html/rfc7230#section-5.4
        host_ += ':' + std::to_string(ep.port());

        // Perform the websocket handshake
        ws_.async_handshake(host_, "/",
            beast::bind_front_handler(
                &session::on_handshake,
                shared_from_this()));
    }

    std::string Json_to_string(const Json::Value& json) {
        Json::StreamWriterBuilder wbuilder;
        wbuilder["indentation"] = ""; // Optional
        return Json::writeString(wbuilder, json);
    }

    void
    on_handshake(beast::error_code ec)
    {
        if(ec) {
            return fail(ec, "handshake");
        }
        
        // Send the message
        ws_.async_write(
            net::buffer(message_text_),
            beast::bind_front_handler(&session::on_write, shared_from_this()));
    }

    void on_write(beast::error_code ec, std::size_t bytes_transferred) {
        boost::ignore_unused(bytes_transferred);

        if(ec)
            return fail(ec, "write");
        
        // Read a message into our buffer
        ws_.async_read(
            buffer_,
            beast::bind_front_handler(
                &session::on_read,
                shared_from_this()));
    }

    void
    on_read(
        beast::error_code ec,
        std::size_t bytes_transferred)
    {
        boost::ignore_unused(bytes_transferred);

        if(ec)
            return fail(ec, "read");

        // Close the WebSocket connection
        ws_.async_close(websocket::close_code::normal,
            beast::bind_front_handler(
                &session::on_close,
                shared_from_this()));
    }

    void
    on_close(beast::error_code ec)
    {
        if(ec)
            return fail(ec, "close");

        // 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;
    }
};

//------------------------------------------------------------------------------

int main()
{
    // auto const host = argv[1];
    // auto const port = argv[1];
    // auto const text = argv[1];

    std::ifstream file("details.json");
    Json::Value actualjson;
    Json::Reader jsonreader;

    jsonreader.parse(file,actualjson);

    // The io_context is required for all I/O
    net::io_context context;

    // Launch the asynchronous operation
    std::make_shared<session>(context)->run("stream.binance.com", "9443",
                                            actualjson);

    // Run the I/O service. The call will return when
    // the socket is closed.
    context.run();

    return EXIT_SUCCESS;
}