Files
cpp-httplib/docs-src/pages/en/cookbook/w01-websocket-echo.md
T
yhirose 9bfd2ddf1c Fix README and docs pages that no longer match the code
Bring the READMEs and the docs pages (en and ja) in line with the
current header:

- Fix the client sample that does not compile, the Transfer-Encoding
  statement for default headers, the verifier callback comment, the
  thread pool spawn rule, the sanitize_filename description, and the
  inverted Accept-Encoding sentence.
- Describe recent behaviour: TLS errors behind Read/Write failures,
  Host validation, Connection: close for a body without length,
  content_reader rules, refused CONNECT, WebSocketClient proxies,
  CPPHTTPLIB_INTERIM_RESPONSE_MAX_COUNT, the SSE event size limit, and
  the payload limit of the Stream API.
- Complete the API references of WebSocket, WebSocketClient and the
  stream:: helpers, and the SSE reconnect rules.
- Fix cookbook pages: keychain loading on every backend, received Close
  status, a multipart sample that trusted the client's file name, an
  echo sample that sent binary as text, SNI, pre-request handler scope,
  stop() with WebSocket handlers, and the thread pool notes.
- Restore the mutex in the LLM app's Chapter 5 code.
2026-10-18 10:13:57 -04:00

3.3 KiB
Raw Blame History

title, order, status
title order status
W01. Implement a WebSocket Echo Server and Client 52 draft

WebSocket is a protocol for two-way messaging between client and server. cpp-httplib provides APIs for both sides. Let's start with the simplest example: an echo server.

Server: echo server

#include <httplib.h>

int main() {
  httplib::Server svr;

  svr.WebSocket("/echo", [](const httplib::Request &req, httplib::ws::WebSocket &ws) {
    std::string msg;
    while (ws.is_open()) {
      auto result = ws.read(msg);
      if (result == httplib::ws::ReadResult::Fail) {
        break;
      }
      // echo back what we received, in the same frame type
      if (result == httplib::ws::ReadResult::Binary) {
        ws.send(msg.data(), msg.size());
      } else {
        ws.send(msg);
      }
    }
  });

  svr.listen("0.0.0.0", 8080);
}

Register a WebSocket handler with svr.WebSocket(). By the time the handler runs, the WebSocket handshake is already complete. Inside the loop, just ws.read() and ws.send() to get a working echo. A binary message goes back through the data() + size() overload so it stays binary (more on that below).

The read() return value is a ReadResult enum:

  • ReadResult::Text: received a text message
  • ReadResult::Binary: received a binary message
  • ReadResult::Fail: error, or connection closed
  • ReadResult::Timeout: a read timeout you set with set_read_timeout() elapsed with nothing received; the connection is still open. The compile-time default timeout closes the connection and is reported as Fail instead — see W06. Set Timeouts

Client: talk to the echo server

#include <httplib.h>

int main() {
  httplib::ws::WebSocketClient cli("ws://localhost:8080/echo");
  if (!cli.connect()) {
    std::cerr << "failed to connect" << std::endl;
    return 1;
  }

  cli.send("Hello, WebSocket!");

  std::string msg;
  if (cli.read(msg) != httplib::ws::ReadResult::Fail) {
    std::cout << "received: " << msg << std::endl;
  }

  cli.close();
}

Use a ws:// (plain) or wss:// (TLS) URL. Call connect() to do the handshake, then send() and read() work the same as on the server side.

Text vs. binary

send() has two overloads that let you choose the frame type.

ws.send("Hello");                        // text frame
ws.send(binary_data, binary_data_size);  // binary frame

The std::string overload sends as text; the const char* + size overload sends as binary. A bit subtle, but once you know it, it's intuitive. See W04. Send and receive binary frames for details.

Thread pool implications

A WebSocket handler holds its worker thread for the entire life of the connection — one connection per thread. The default pool already grows under load, up to 4× its base thread count. For many concurrent clients, raise that maximum.

svr.new_task_queue = [] {
  return new httplib::ThreadPool(8, 128);
};

See S21. Configure the thread pool.

Note: To run WebSocket over HTTPS, use httplib::SSLServer instead of httplib::Server — the same WebSocket() handler just works. On the client side, use a wss:// URL. For CA and client certificate configuration, see W05. Configure TLS for wss:// Connections.