Implementation:ClickHouse ClickHouse Poco WebSocket
| Knowledge Sources | |
|---|---|
| Domains | Networking, WebSocket |
| Last Updated | 2026-02-08 00:00 GMT |
Overview
WebSocket protocol implementation (RFC 6455) supporting both client and server-side bidirectional communication over HTTP.
Description
The Poco `WebSocket` class implements the WebSocket protocol as specified in RFC 6455, enabling full-duplex communication over a single TCP connection. It extends `StreamSocket` and supports both client-side connections (via `HTTPClientSession`) and server-side connections (from `HTTPServerRequest`).
The implementation handles WebSocket framing (text, binary, control frames), masking requirements for client messages, frame fragmentation, and various control messages (PING, PONG, CLOSE). It supports configurable maximum payload sizes to prevent memory exhaustion attacks and provides methods for sending and receiving WebSocket frames with appropriate flags and opcodes.
Usage
ClickHouse uses this vendored Poco component for WebSocket-based communication, enabling real-time bidirectional data exchange with clients or external services over HTTP connections upgraded to WebSocket protocol.
Code Reference
Source Location
- Repository: ClickHouse
- File: base/poco/Net/include/Poco/Net/WebSocket.h
- Lines: 1-301
Signature
class WebSocket : public StreamSocket {
public:
enum Mode {
WS_SERVER,
WS_CLIENT
};
enum FrameFlags {
FRAME_FLAG_FIN = 0x80,
FRAME_FLAG_RSV1 = 0x40,
FRAME_FLAG_RSV2 = 0x20,
FRAME_FLAG_RSV3 = 0x10
};
enum FrameOpcodes {
FRAME_OP_CONT = 0x00,
FRAME_OP_TEXT = 0x01,
FRAME_OP_BINARY = 0x02,
FRAME_OP_CLOSE = 0x08,
FRAME_OP_PING = 0x09,
FRAME_OP_PONG = 0x0a,
FRAME_OP_BITMASK = 0x0f,
FRAME_OP_SETRAW = 0x100
};
enum SendFlags {
FRAME_TEXT = FRAME_FLAG_FIN | FRAME_OP_TEXT,
FRAME_BINARY = FRAME_FLAG_FIN | FRAME_OP_BINARY
};
enum StatusCodes {
WS_NORMAL_CLOSE = 1000,
WS_ENDPOINT_GOING_AWAY = 1001,
WS_PROTOCOL_ERROR = 1002,
WS_PAYLOAD_NOT_ACCEPTABLE = 1003,
WS_MALFORMED_PAYLOAD = 1007,
WS_POLICY_VIOLATION = 1008,
WS_PAYLOAD_TOO_BIG = 1009,
WS_EXTENSION_REQUIRED = 1010,
WS_UNEXPECTED_CONDITION = 1011
};
enum ErrorCodes {
WS_ERR_NO_HANDSHAKE = 1,
WS_ERR_HANDSHAKE_NO_VERSION = 2,
WS_ERR_HANDSHAKE_UNSUPPORTED_VERSION = 3,
WS_ERR_HANDSHAKE_NO_KEY = 4,
WS_ERR_HANDSHAKE_ACCEPT = 5,
WS_ERR_UNAUTHORIZED = 6,
WS_ERR_PAYLOAD_TOO_BIG = 10,
WS_ERR_INCOMPLETE_FRAME = 11
};
WebSocket(HTTPServerRequest& request, HTTPServerResponse& response);
WebSocket(HTTPClientSession& cs, HTTPRequest& request, HTTPResponse& response);
WebSocket(HTTPClientSession& cs, HTTPRequest& request, HTTPResponse& response,
HTTPCredentials& credentials);
WebSocket(const Socket& socket);
WebSocket& operator=(const Socket& socket);
void shutdown();
void shutdown(Poco::UInt16 statusCode, const std::string& statusMessage = "");
int sendFrame(const void* buffer, int length, int flags = FRAME_TEXT);
int receiveFrame(void* buffer, int length, int& flags);
int receiveFrame(Poco::Buffer<char>& buffer, int& flags);
Mode mode() const;
void setMaxPayloadSize(int maxPayloadSize);
int getMaxPayloadSize() const;
static const std::string WEBSOCKET_VERSION;
};
Import
#include <Poco/Net/WebSocket.h>
I/O Contract
| Input | Output |
|---|---|
| HTTP upgrade request/response | Established WebSocket connection |
| Frame data with flags and opcode | Sent WebSocket frame with proper framing |
| Receive buffer and capacity | Received frame data and flags |
| Status code and message for shutdown | Proper CLOSE frame sent |
WebSocket Frame Types
| Opcode | Frame Type | Description |
|---|---|---|
| `FRAME_OP_TEXT` | Text Frame | UTF-8 encoded text data |
| `FRAME_OP_BINARY` | Binary Frame | Binary application data |
| `FRAME_OP_CLOSE` | Close Frame | Connection close with status |
| `FRAME_OP_PING` | Ping Frame | Keep-alive ping |
| `FRAME_OP_PONG` | Pong Frame | Response to ping |
| `FRAME_OP_CONT` | Continuation | Continuation of fragmented message |
Usage Examples
// Server-side WebSocket (in HTTP request handler)
void handleRequest(HTTPServerRequest& request, HTTPServerResponse& response) {
try {
WebSocket ws(request, response);
ws.setMaxPayloadSize(1024 * 1024); // 1 MB max
// Receive messages
char buffer[1024];
int flags;
int n;
while ((n = ws.receiveFrame(buffer, sizeof(buffer), flags)) > 0) {
int opcode = flags & WebSocket::FRAME_OP_BITMASK;
if (opcode == WebSocket::FRAME_OP_TEXT) {
std::string msg(buffer, n);
std::cout << "Received text: " << msg << std::endl;
// Echo back
ws.sendFrame(buffer, n, WebSocket::FRAME_TEXT);
}
else if (opcode == WebSocket::FRAME_OP_BINARY) {
std::cout << "Received " << n << " bytes of binary data" << std::endl;
ws.sendFrame(buffer, n, WebSocket::FRAME_BINARY);
}
else if (opcode == WebSocket::FRAME_OP_PING) {
// Send PONG response
ws.sendFrame(buffer, n, WebSocket::FRAME_OP_PONG);
}
else if (opcode == WebSocket::FRAME_OP_CLOSE) {
std::cout << "Close frame received" << std::endl;
break;
}
}
ws.shutdown(WebSocket::WS_NORMAL_CLOSE);
}
catch (WebSocketException& exc) {
// Handle WebSocket-specific errors
std::cerr << "WebSocket error: " << exc.displayText() << std::endl;
}
}
// Client-side WebSocket
HTTPClientSession cs("echo.websocket.org", 80);
HTTPRequest request(HTTPRequest::HTTP_GET, "/");
HTTPResponse response;
WebSocket ws(cs, request, response);
// Send text message
std::string msg = "Hello, WebSocket!";
ws.sendFrame(msg.data(), msg.length(), WebSocket::FRAME_TEXT);
// Send binary message
std::vector<unsigned char> data = {0x01, 0x02, 0x03, 0x04};
ws.sendFrame(data.data(), data.size(), WebSocket::FRAME_BINARY);
// Receive response
Poco::Buffer<char> recvBuffer(0);
int flags;
int n = ws.receiveFrame(recvBuffer, flags);
if (n > 0) {
int opcode = flags & WebSocket::FRAME_OP_BITMASK;
if (opcode == WebSocket::FRAME_OP_TEXT) {
std::string response(recvBuffer.begin(), n);
std::cout << "Received: " << response << std::endl;
}
}
// Send PING
ws.sendFrame("", 0, WebSocket::FRAME_OP_PING | WebSocket::FRAME_FLAG_FIN);
// Wait for PONG
n = ws.receiveFrame(recvBuffer, flags);
if ((flags & WebSocket::FRAME_OP_BITMASK) == WebSocket::FRAME_OP_PONG) {
std::cout << "PONG received" << std::endl;
}
// Graceful close
ws.shutdown(WebSocket::WS_NORMAL_CLOSE, "Goodbye");
// Handle authentication (client-side)
HTTPCredentials creds("username", "password");
WebSocket authWs(cs, request, response, creds);