4.0 KiB
title, order
| title | order |
|---|---|
| WebSocket | 8 |
cpp-httplib supports WebSocket as well. Unlike HTTP request/response, WebSocket lets the server and client exchange messages in both directions. It's great for chat apps and real-time notifications.
Let's build an echo server and client right away.
Echo Server
Here's an echo server that sends back whatever message it receives.
#include "httplib.h"
#include <iostream>
int main() {
httplib::Server svr;
svr.WebSocket("/ws", [](const httplib::Request &, httplib::ws::WebSocket &ws) {
std::string msg;
while (ws.read(msg)) {
ws.send(msg); // Send back the received message as-is
}
});
std::cout << "Listening on port 8080..." << std::endl;
svr.listen("0.0.0.0", 8080);
}
You register a WebSocket handler with svr.WebSocket(). It works just like svr.Get() and svr.Post() from Chapter 3.
Inside the handler, ws.read(msg) waits for a message. When the connection closes, read() returns false, so the loop exits. ws.send(msg) sends a message back.
Connecting from a Client
Let's connect to the server using httplib::ws::WebSocketClient.
#include "httplib.h"
#include <iostream>
int main() {
httplib::ws::WebSocketClient client("ws://localhost:8080/ws");
if (!client.connect()) {
std::cout << "Connection failed" << std::endl;
return 1;
}
// Send a message
client.send("Hello, WebSocket!");
// Receive a response from the server
std::string msg;
if (client.read(msg)) {
std::cout << msg << std::endl; // Hello, WebSocket!
}
client.close();
}
Pass a URL in ws://host:port/path format to the constructor. Call connect() to start the connection, then use send() and read() to exchange messages.
Text and Binary
WebSocket has two types of messages: text and binary. You can tell them apart by the return value of read().
svr.WebSocket("/ws", [](const httplib::Request &, httplib::ws::WebSocket &ws) {
std::string msg;
httplib::ws::ReadResult ret;
while ((ret = ws.read(msg))) {
if (ret == httplib::ws::Binary) {
ws.send(msg.data(), msg.size()); // Send as binary
} else {
ws.send(msg); // Send as text
}
}
});
ws.send(const std::string &)— sends as a text messagews.send(const char *, size_t)— sends as a binary message
The client-side API is the same.
Accessing Request Information
You can read HTTP request information from the handshake through the first argument req in the handler. This is handy for checking authentication tokens.
svr.WebSocket("/ws", [](const httplib::Request &req, httplib::ws::WebSocket &ws) {
auto token = req.get_header_value("Authorization");
if (token.empty()) {
ws.close(httplib::ws::CloseStatus::PolicyViolation, "unauthorized");
return;
}
std::string msg;
while (ws.read(msg)) {
ws.send(msg);
}
});
A check inside the handler runs after the handshake has completed. To refuse the connection with an HTTP status such as 401 before it is upgraded, use set_pre_request_handler() instead. It also runs for WebSocket routes. See S11. Authenticate per route with a pre-request handler.
Using WSS
WebSocket over HTTPS (WSS) is also supported. On the server side, just register a WebSocket handler on httplib::SSLServer.
httplib::SSLServer svr("cert.pem", "key.pem");
svr.WebSocket("/ws", [](const httplib::Request &, httplib::ws::WebSocket &ws) {
std::string msg;
while (ws.read(msg)) {
ws.send(msg);
}
});
svr.listen("0.0.0.0", 8443);
On the client side, use the wss:// scheme.
httplib::ws::WebSocketClient client("wss://localhost:8443/ws");
Next Steps
Now you know the basics of WebSocket. This wraps up the Tour.
The next page gives you a summary of features we didn't cover in the Tour.
Next: What's Next