libwebsockets clib Networking / WebSocket

C WebSocket server and client for PascalAI. RFC 6455 full-duplex messaging, TLS, HTTP/1.1 and HTTP/2, per-message deflate compression, and a built-in event loop — all from a battle-tested C library used in production on everything from IoT devices to cloud services.

ppm install libwebsockets

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.

CLib package

Requires libwebsockets-dev. Ubuntu/Debian: sudo apt install libwebsockets-dev

Key Features

FeatureDetails
WebSocket RFC 6455Full-duplex text and binary frames, fragmentation, masking
HTTP/1.1Static file serving, REST endpoints, chunked transfer encoding
HTTP/2Multiplexed streams over a single TCP connection, server push
TLSOpenSSL, mbedTLS, or wolfSSL backends; client and mutual TLS
CompressionPer-message deflate (RFC 7692) for reduced bandwidth
Event loopBuilt-in poll/epoll/kqueue loop; blocking Run or non-blocking RunOnce
ProtocolsMultiple named protocol handlers per server on a single port
MQTTLightweight pub/sub messaging over WebSocket transport

Comparison

LibraryLanguageNotes
libwebsockets (LWS)CVery low overhead, widely deployed, good for IoT and embedded
ws (Node.js)JavaScriptHigher memory overhead from V8; LWS wins on raw throughput and footprint
uWebSocketsC/C++Both are C-level performance; LWS has a larger community and longer track record
Socket.IOJavaScriptAdds 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

FieldTypeDescription
PortIntegerListening port for server; 0 in client mode
HoststringBind address for server ('0.0.0.0') or hostname for client
PathstringURL path used for client connections (e.g. '/ws')
UseTLSBooleanEnable TLS via the configured backend
CertPathstringPath to PEM certificate file (server TLS)
KeyPathstringPath to PEM private key file (server TLS)
CAPathstringPath to CA bundle for peer certificate verification
Protocolsarray of stringSupported sub-protocol names for negotiation
MaxClientsIntegerMaximum concurrent connections; 0 means unlimited
PingIntervalIntegerSeconds between automatic ping frames; 0 disables keepalive

TLWSMessageType

ValueConstantMeaning
1mtTextUTF-8 text frame (RFC 6455 opcode 0x1)
2mtBinaryBinary frame (RFC 6455 opcode 0x2)
8mtCloseConnection close frame
9mtPingPing frame; LWS auto-replies with pong
10mtPongPong frame in response to a ping

TLWSMessage

FieldTypeDescription
ClientTLWSClientHandle of the connection that sent this message
MsgTypeTLWSMessageTypeFrame type (text, binary, ping, pong, close)
DatastringPayload bytes as a string (binary data is raw bytes)
FinalBooleanTrue when this is the last fragment of a fragmented message

TLWSClientInfo

FieldTypeDescription
RemoteIPstringClient IP address as a dotted-decimal or IPv6 string
ProtocolstringNegotiated sub-protocol name (empty if none)
UserAgentstringHTTP User-Agent header from the upgrade request
Headersarray of recordAll 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.

FunctionDescription
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.

FunctionDescription
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.

FunctionDescription
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
Tip — message loop pattern

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.

FunctionDescription
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.

FunctionDescription
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.

FunctionDescription
ServeStatic(Ctx, URLPath, DirPath)Mount the local directory DirPath at URLPath for HTTP GET requests
LWSVersionReturns 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

Version1.0.0
Typeclib
C Librarylibwebsockets-dev
Authorgustavo

System Requirements

libwebsockets-dev

Ubuntu/Debian:
sudo apt install libwebsockets-dev

TLWSMessageType

mtText = 1 — UTF-8 text frame
mtBinary = 2 — binary frame
mtClose = 8 — close frame
mtPing = 9 — ping frame
mtPong = 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

See Also

  • libuv (event loop)
  • nats (pub/sub messaging)
  • curl (HTTP client)
  • grpc (RPC over HTTP/2)