c++boostbeast-websockets

How to handle ping request on client (boost::beast::websocket)


Imagine that you have some websocket client, that downloading some data in loop like this:

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

#include "nlohmann/json.hpp"

namespace beast = boost::beast;
namespace websocket = beast::websocket;
using tcp = boost::asio::ip::tcp;
class Client {
 public:
  Client(boost::asio::io_context &ctx) : ws_{ctx}, ctx_{ctx} {
    ws_.set_option(websocket::stream_base::timeout::suggested(boost::beast::role_type::client));

#define HOST "127.0.0.1"
#define PORT "8000"
    boost::asio::connect(ws_.next_layer(), tcp::resolver{ctx_}.resolve(HOST, PORT));
    ws_.handshake(HOST ":" PORT, "/api/v1/music");
#undef HOST
#undef PORT
  }

  ~Client() {
    if (ws_.is_open()) {
      ws_.close(websocket::normal);
    }
  }

  nlohmann::json NextPacket(std::size_t offset) {
    nlohmann::json request;
    request["offset"] = offset;
    ws_.write(boost::asio::buffer(request.dump()));

    beast::flat_buffer buffer;
    ws_.read(buffer);
    return nlohmann::json::parse(std::string_view{reinterpret_cast<const char *>(buffer.data().data()), buffer.size()});
  }

 private:
  boost::beast::websocket::stream<boost::asio::ip::tcp::socket> ws_;
  boost::asio::io_context &ctx_;
};

// ... some function
int main() {
  boost::asio::io_context context;
  boost::asio::executor_work_guard<boost::asio::io_context::executor_type> guard{context.get_executor()};
  std::thread{[&context]() { context.run(); }}.detach();
  static constexpr std::size_t kSomeVeryBigConstant{1'000'000'000};
  Client client{context};
  std::size_t offset{};
  while (offset < kSomeVeryBigConstant) {
    offset += client.NextPacket(offset)["offset"].get<std::size_t>();
    // UPDATE:
    userDefinedLongPauseHere();
  }
}

On the server side we have ping requests with some frequency. Were should I handle ping requests? As I understand it, control_callback controls calls to ping, pong and close functions, not requests. With the read or read_async functions, I also cannot catch the ping request.


Solution

  • Beast responds to pings with pongs automatically, as described here: https://github.com/boostorg/beast/issues/899#issuecomment-346333014

    Whenever you call read(), it can process a ping and send a pong without you knowing about that.