Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

I'm new to beast and trying to create a websocket client which will subscribe to a websocket event in the remote server and start to listen for incoming messages forever unless I or the server explicitly close the connection.

For now, I am using the the async_sll_websocket_client example that is in the github repository of the beast.

#include "example/common/root_certificates.hpp"
#include <boost/beast/core.hpp>
#include <boost/beast/ssl.hpp>
#include <boost/beast/websocket.hpp>
#include <boost/beast/websocket/ssl.hpp>
#include <boost/asio/strand.hpp>
#include <cstdlib>
#include <functional>
#include <iostream>
#include <memory>
#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>
//------------------------------------------------------------------------------
// Report a failure
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::ssl_stream<beast::tcp_stream>> ws_;
    beast::flat_buffer buffer_;
    std::string host_;
    std::string text_;
public:
    // Resolver and socket require an io_context
    explicit
    session(net::io_context& ioc, ssl::context& ctx)
        : resolver_(net::make_strand(ioc))
        , ws_(net::make_strand(ioc), ctx)
    // Start the asynchronous operation
        char const* host,
        char const* port,
        char const* text)
        // Save these for later
        host_ = host;
        text_ = text;
        // Look up the domain name
        resolver_.async_resolve(
            host,
            port,
            beast::bind_front_handler(
                &session::on_resolve,
                shared_from_this()));
    on_resolve(
        beast::error_code ec,
        tcp::resolver::results_type results)
        if(ec)
            return fail(ec, "resolve");
        // Set a timeout on 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()));
    on_connect(beast::error_code ec, tcp::resolver::results_type::endpoint_type ep)
        if(ec)
            return fail(ec, "connect");
        // 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());
        // Set a timeout on the operation
        beast::get_lowest_layer(ws_).expires_after(std::chrono::seconds(30));
        // Perform the SSL handshake
        ws_.next_layer().async_handshake(
            ssl::stream_base::client,
            beast::bind_front_handler(
                &session::on_ssl_handshake,
                shared_from_this()));
    on_ssl_handshake(beast::error_code ec)
        if(ec)
            return fail(ec, "ssl_handshake");
        // 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-ssl");
        // Perform the websocket handshake
        ws_.async_handshake(host_, "/",
            beast::bind_front_handler(
                &session::on_handshake,
                shared_from_this()));
    on_handshake(beast::error_code ec)
        if(ec)
            return fail(ec, "handshake");
        // Send the message
        ws_.async_write(
            net::buffer(text_),
            beast::bind_front_handler(
                &session::on_write,
                shared_from_this()));
    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()));
    on_read(
        beast::error_code ec,
        std::size_t bytes_transferred)
        boost::ignore_unused(bytes_transferred);
        if(ec)
            return fail(ec, "read");
        //here I try to read the buffer again instead of ccalling the async_close.
        ws_.async_read(
            buffer_,
            beast::bind_front_handler(
                &session::on_read,
                shared_from_this()));
        // Close the WebSocket connection
        //ws_.async_close(websocket::close_code::normal,
        //    beast::bind_front_handler(
        //        &session::on_close,
        //        shared_from_this()));
    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-ssl <host> <port> <text>\n" <<
            "Example:\n" <<
            "    websocket-client-async-ssl echo.websocket.org 443 \"Hello, world!\"\n";
        return EXIT_FAILURE;
    auto const host = argv[1];
    auto const port = argv[2];
    auto const text = argv[3];
    // 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);
    // Launch the asynchronous operation
    std::make_shared<session>(ioc, ctx)->run(host, port, text);
    // Run the I/O service. The call will return when
    // the socket is closed.
    ioc.run();
    return EXIT_SUCCESS;

So far, I tried to call the async_read again in the on_read function and invoke the on_readrecursively. The connection doesn't close this way but ``on_read```doesn't get invoked second time. Is there a pattern which I can apply to continuously listen to incoming messages from server??

EDIT: Apparently my approach was correct, I just needed to send subscribe message one more time after the first on_readcall.

This function might have terminated immediately after the first read which was the response for the write(code). Try this code, to keep looking for message as long as the socket is open.

        net::io_context ioc;
        auto const host = "localhost";
        auto const  port = "1234";
        auto const  port = "SOME TEXT";
        // Launch the asynchronous operation
        std::shared_ptr<session> p = std::make_shared<session>(ioc);
        p->run(host, port, text);
        ioc.run();
        while (p->is_socket_open()) {
            ioc.restart();              
            p->enable_async_read();
            ioc.run();

implementation for enable_async_read & is_socket_open

void session::enable_async_read() {
ws_.async_read(
    buffer_,
    beast::bind_front_handler(
        &session::on_read,
        shared_from_this()));
bool session::is_socket_open() {
return ws_.is_open();
        

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.