The server API is declared by one header, with the examples' support header alongside it:
#include <vws/server.h> #include "vwsx.h"
Each worker thread is given its own context by a constructor and destructor. Here the context is just a label, to show the lifecycle:
static void* worker_ctor(void* data)
{
(void)data;
return vws.strdup("worker-ctx");
}
static void worker_dtor(void* ctx)
{
vws.free(ctx);
}The constructor's return value becomes the ctx passed to
the data callback on that thread, and the destructor frees it when the thread
exits. vws.strdup and vws.free are the
library's allocator-aware helpers. A real server would use this context for
per-thread resources such as a database handle.
The processing callback echoes the inbound bytes. It receives a
vws_svr_data — a heap-allocated blob
carrying the received bytes, the originating connection id, and a back pointer to
the server — and the worker context (unused here):
static void echo(vws_svr_data* req, void* ctx)
{
(void)ctx;
char* data = (char*)vws.malloc(req->size);
memcpy(data, req->data, req->size);
vws_svr_data* reply = vws_svr_data_own(req->server, req->cid,
(ucstr)data, req->size);
vws_svr_data_free(req);
vws_tcp_svr_send(reply);
}The handler copies the request payload into a fresh buffer and wraps it in
a response with
vws_svr_data_own(), which takes
ownership of that buffer and binds the reply to the same connection id. The
original request is released with
vws_svr_data_free(), and the reply is
queued for the networking thread with
vws_tcp_svr_send().
The server is created and wired up in main:
vws_tcp_svr* server = vws_tcp_svr_new(10, 0, 0);
if (server == NULL)
{
vwsx_die("vws_tcp_svr_new() failed");
}
server->on_data_in = echo;
server->worker_ctor = worker_ctor;
server->worker_dtor = worker_dtor;vws_tcp_svr_new() takes three
arguments: the number of worker threads, the listen backlog, and the
request/response queue size; passing zero for either of the latter two selects
its default (128 and 1024 respectively). The echo handler is installed on
on_data_in and the worker hooks on
worker_ctor and worker_dtor.
The server is then set up to stop cleanly, run, and be freed:
vwsx_serve_stop_on_signal(server); vws_tcp_svr_run(server, HOST, PORT); vws_tcp_svr_free(server);
vwsx_serve_stop_on_signal installs
SIGINT/SIGTERM handlers that stop the
server; because this is the base server, it is passed directly, with no cast.
vws_tcp_svr_run() then blocks, serving
connections until a signal triggers
vws_tcp_svr_stop(), after which
vws_tcp_svr_free() releases the
server.