Overview
libwebsockets wraps LWS — the lightweight C library for WebSocket servers and clients that powers everything from embedded firmware to high-throughput cloud proxies. It implements RFC 6455 WebSocket framing, HTTP/1.1 static serving, HTTP/2 multiplexing, and pluggable TLS backends (OpenSSL, mbedTLS, wolfSSL).
You create a context with NewServer, run the built-in event loop, and receive messages via WaitMessage or PollMessage. Multiple protocol handlers can share one port alongside HTTP file serving. For client mode, Connect returns a handle you can send and receive on directly.
Requires libwebsockets-dev. Ubuntu/Debian: sudo apt install libwebsockets-dev
Key Features
| Feature | Details |
|---|---|
| WebSocket RFC 6455 | Full-duplex text and binary frames, fragmentation, masking |
| HTTP/1.1 | Static file serving, REST endpoints, chunked transfer encoding |
| HTTP/2 | Multiplexed streams over a single TCP connection, server push |
| TLS | OpenSSL, mbedTLS, or wolfSSL backends; client and mutual TLS |
| Compression | Per-message deflate (RFC 7692) for reduced bandwidth |
| Event loop | Built-in poll/epoll/kqueue loop; blocking Run or non-blocking RunOnce |
| Protocols | Multiple named protocol handlers per server on a single port |
| MQTT | Lightweight pub/sub messaging over WebSocket transport |
Comparison
| Library | Language | Notes |
|---|---|---|
| libwebsockets (LWS) | C | Very low overhead, widely deployed, good for IoT and embedded |
| ws (Node.js) | JavaScript | Higher memory overhead from V8; LWS wins on raw throughput and footprint |
| uWebSockets | C/C++ | Both are C-level performance; LWS has a larger community and longer track record |
| Socket.IO | JavaScript | Adds polling fallbacks and namespaces; LWS is pure RFC 6455 WebSocket |
Quick Start
WebSocket echo server
uses libwebsockets;
var opts: TLWSOptions;
opts.Port := 8080;
opts.Host := '0.0.0.0';
opts.UseTLS := False;
opts.MaxClients := 0; { unlimited }
opts.PingInterval := 30;
var ctx := NewServer(opts);
WriteLn('WebSocket server listening on :8080');
var msg: TLWSMessage;
while True do
begin
RunOnce(ctx, 50); { process events, 50 ms max wait }
if PollMessage(ctx, msg) then
begin
if msg.MsgType = mtText then
SendText(msg.Client, msg.Data) { echo back }
else if msg.MsgType = mtClose then
CloseClient(msg.Client, 1000, 'Normal closure');
end;
end;
Stop(ctx);
FreeContext(ctx);
Broadcast to all clients
uses libwebsockets;
var opts: TLWSOptions;
opts.Port := 9000;
opts.Host := '0.0.0.0';
opts.UseTLS := False;
var ctx := NewServer(opts);
WriteLn(ClientCount(ctx), ' clients connected');
{ Send a JSON update to every connected client }
BroadcastText(ctx, '{"event":"tick","ts":' + IntToStr(Now) + '}');
{ Or iterate for targeted sends }
var clients := GetClients(ctx);
for var i := 0 to Length(clients) - 1 do
begin
var info := GetClientInfo(clients[i]);
WriteLn('Client from: ' + info.RemoteIP + ' proto: ' + info.Protocol);
SendText(clients[i], 'Hello, ' + info.RemoteIP);
end;
Client connection
uses libwebsockets;
{ Connect to a remote WebSocket server }
var client := Connect('wss://echo.websocket.org', 'chat');
if IsConnected(client) then
begin
SendText(client, 'Hello from PascalAI!');
{ Wait up to 3 s for a reply }
var ctx := 0; { client mode: ctx not used for WaitMessage }
var msg: TLWSMessage;
if WaitMessage(ctx, 3000, msg) then
WriteLn('Got: ' + msg.Data);
Disconnect(client);
end;
Types
TLWSContext
Opaque handle for a server or client context returned by NewServer. Pass to Run, RunOnce, BroadcastText, PollMessage, WaitMessage, and Stop/FreeContext.
TLWSClient
Opaque handle for an individual WebSocket connection. Returned by Connect/ConnectEx in client mode, or carried inside TLWSMessage.Client in server mode. Pass to SendText, SendBinary, SendPing, CloseClient, IsConnected, and GetClientInfo.
TLWSOptions
| Field | Type | Description |
|---|---|---|
| Port | Integer | Listening port for server; 0 in client mode |
| Host | string | Bind address for server ('0.0.0.0') or hostname for client |
| Path | string | URL path used for client connections (e.g. '/ws') |
| UseTLS | Boolean | Enable TLS via the configured backend |
| CertPath | string | Path to PEM certificate file (server TLS) |
| KeyPath | string | Path to PEM private key file (server TLS) |
| CAPath | string | Path to CA bundle for peer certificate verification |
| Protocols | array of string | Supported sub-protocol names for negotiation |
| MaxClients | Integer | Maximum concurrent connections; 0 means unlimited |
| PingInterval | Integer | Seconds between automatic ping frames; 0 disables keepalive |
TLWSMessageType
| Value | Constant | Meaning |
|---|---|---|
| 1 | mtText | UTF-8 text frame (RFC 6455 opcode 0x1) |
| 2 | mtBinary | Binary frame (RFC 6455 opcode 0x2) |
| 8 | mtClose | Connection close frame |
| 9 | mtPing | Ping frame; LWS auto-replies with pong |
| 10 | mtPong | Pong frame in response to a ping |
TLWSMessage
| Field | Type | Description |
|---|---|---|
| Client | TLWSClient | Handle of the connection that sent this message |
| MsgType | TLWSMessageType | Frame type (text, binary, ping, pong, close) |
| Data | string | Payload bytes as a string (binary data is raw bytes) |
| Final | Boolean | True when this is the last fragment of a fragmented message |
TLWSClientInfo
| Field | Type | Description |
|---|---|---|
| RemoteIP | string | Client IP address as a dotted-decimal or IPv6 string |
| Protocol | string | Negotiated sub-protocol name (empty if none) |
| UserAgent | string | HTTP User-Agent header from the upgrade request |
| Headers | array of record | All HTTP upgrade headers as Key/Value pairs |
Server API
Create a context, optionally mount static files, then drive the event loop with Run or RunOnce.
| Function | Description |
|---|---|
| NewServer(Opts) | Create a WebSocket server context bound to Opts.Port |
| Run(Ctx) | Run the event loop until Stop is called (blocking) |
| RunOnce(Ctx, TimeoutMs) | Process events for at most TimeoutMs milliseconds then return |
| Stop(Ctx) | Signal the event loop to exit cleanly |
| FreeContext(Ctx) | Destroy the context and release all connections and memory |
Send API
Send messages to individual clients or broadcast to all connected clients at once.
| Function | Description |
|---|---|
| SendText(Client, Data) | Send a UTF-8 text frame to one client |
| SendBinary(Client, Data) | Send a binary frame to one client |
| BroadcastText(Ctx, Data) | Send a text frame to every connected client |
| BroadcastBinary(Ctx, Data) | Send a binary frame to every connected client |
| SendPing(Client, Data) | Send a ping frame; LWS will expect a pong in return |
| CloseClient(Client, Code, Reason) | Send a close frame with a numeric status code and reason string, then disconnect |
Receive API
Pull messages from the internal receive queue. Use RunOnce to pump events into the queue before polling.
| Function | Description |
|---|---|
| PollMessage(Ctx, out Msg) | Non-blocking check; returns True and fills Msg if a message is queued |
| WaitMessage(Ctx, TimeoutMs, out Msg) | Block for up to TimeoutMs ms until a message arrives; returns False on timeout |
Call RunOnce first to pump the event loop, then PollMessage in a tight loop until it returns False, then repeat. This keeps latency low while staying single-threaded.
Client Mode API
Connect to a remote WebSocket server and exchange messages using the same Send/Receive functions as the server side.
| Function | Description |
|---|---|
| Connect(URL, Protocol) | Connect to ws:// or wss:// URL with the given sub-protocol name |
| ConnectEx(Opts) | Connect with full TLWSOptions control (TLS certs, custom headers, path) |
| Disconnect(Client) | Send close frame and tear down the connection |
| IsConnected(Client) | Returns True if the connection is open and ready to send |
Connection Info API
Inspect connected clients from the server side.
| Function | Description |
|---|---|
| ClientCount(Ctx) | Number of currently connected clients |
| GetClientInfo(Client) | Returns a TLWSClientInfo record with IP, protocol, user-agent, and headers |
| GetClients(Ctx) | Returns an array of all active TLWSClient handles |
HTTP Serving API
LWS can serve static files over HTTP on the same port as the WebSocket listener, useful for hosting a browser client alongside the WebSocket endpoint.
| Function | Description |
|---|---|
| ServeStatic(Ctx, URLPath, DirPath) | Mount the local directory DirPath at URLPath for HTTP GET requests |
| LWSVersion | Returns the linked libwebsockets version string (e.g. '4.3.3') |
uses libwebsockets;
var opts: TLWSOptions;
opts.Port := 8080;
opts.Host := '0.0.0.0';
opts.UseTLS := False;
var ctx := NewServer(opts);
{ Serve ./public/ at http://localhost:8080/ }
ServeStatic(ctx, '/', './public');
WriteLn('LWS version: ' + LWSVersion);
Run(ctx); { blocking }
FreeContext(ctx);
TLS Server
Enable UseTLS and provide certificate paths in TLWSOptions. The TLS backend (OpenSSL by default on Linux) is selected at compile time of libwebsockets-dev.
uses libwebsockets;
var opts: TLWSOptions;
opts.Port := 443;
opts.Host := '0.0.0.0';
opts.UseTLS := True;
opts.CertPath := '/etc/ssl/certs/server.crt';
opts.KeyPath := '/etc/ssl/private/server.key';
opts.CAPath := '/etc/ssl/certs/ca-bundle.crt';
var ctx := NewServer(opts);
WriteLn('Secure WebSocket server on :443');
Run(ctx);
Package Info
System Requirements
libwebsockets-devUbuntu/Debian:
sudo apt install libwebsockets-dev
TLWSMessageType
mtText = 1 — UTF-8 text framemtBinary = 2 — binary framemtClose = 8 — close framemtPing = 9 — ping framemtPong = 10 — pong frame
Functions
- NewServer
- Run / RunOnce
- Stop / FreeContext
- SendText / SendBinary
- BroadcastText / BroadcastBinary
- SendPing / CloseClient
- PollMessage / WaitMessage
- Connect / ConnectEx
- Disconnect / IsConnected
- ClientCount / GetClients
- GetClientInfo
- ServeStatic
- LWSVersion