NNG_CTX(5)
π NNG_CTX(5) π
okay bestie, welcome to nng_ctx β this is the protocol context page from the NNG Reference Manual, and honestly? it's kind of a big deal. sit down, grab a strawberry π, let's get into it.
β¨ NAME β¨
nng_ctx β protocol context. yes queen, that's the whole name. short, iconic, to the point.
β¨ SYNOPSIS β¨
#include <nng/nng.h>
typedef struct nng_ctx_s nng_ctx
literally that's it. that's the whole vibe. π
β¨ DESCRIPTION β¨
so an nng_ctx is a handle to an underlying context object, and that object is the thing that keeps the protocol state for some stateful protocols. the whole point of having a separate context object is so apps can share a single socket β with all its various underlying dialers, listeners, and pipes β while STILL getting the benefit of separate state tracking. sharing is caring but the state stays yours. π«Ά
for example, a req context is gonna contain the request ID of any sent request, a timer to retry the request on failure, and so forth. and a separate context on that same socket can have the same kind of data, except it corresponds to a completely different request. no cap.
Important π¨ The nng_ctx structure is always passed by value β both for input parameters and return values β and should be treated opaquely. Passing structures this way gives the compiler a chance to perform accurate type checks in functions passing values of this type. so likeβ¦ don't go poking around in there. the compiler is doing its little checks, let it cook. π
all contexts share the same socket, which means some options, plus the underlying transport details, are gonna be common to all contexts on that socket. it's giving group project energy in the best way possible.
Note π Not every protocol supports separate contexts. peek at the protocol-specific documentation for the deets on whether contexts are even supported, and what options are supported for contexts.
protocols that make use of contexts will also have a default context, and that's the one used when the socket global operations are used. operations using the global context will generally not interfere with any other contexts β except that certain socket options may affect socket global behavior. mostly chill, occasionally messy, iykyk.
historically π applications that wanted to use a stateful protocol concurrently had to resort to raw mode sockets, which bypasses much of the various protocol handling and leaves it up to the application to do it. contexts make it possible to still benefit from advanced protocol handling β including timeouts, retries, and matching requests to responses β while doing so concurrently. glow-up era. β¨
Note π Raw mode sockets do not support contexts, since there is generally no state tracked for them, and thus contexts make no sense.
Tip π‘ Contexts are an excellent mechanism to use when building concurrent applications, and should be used in lieu of raw mode sockets when possible. slay.
Important β οΈ Use of file descriptor polling (with descriptors obtained using theNNG_OPT_RECVFDorNNG_OPT_SENDFDoptions) while contexts are in use on the same socket is not supported, and may lead to unpredictable behavior. These asynchronous methods should not be mixed on the same socket. do not do this. fr fr.
πΈ Initialization πΈ
A context may be initialized using the macro NNG_CTX_INITIALIZER before it is opened, to prevent confusion with valid open contexts.
β¨ EXAMPLE β¨
okay here's the moment you've been waiting for π. the following program fragment demonstrates the use of contexts to implement a concurrent rep service that simply echos messages back to the sender.
struct echo_context {
nng_ctx ctx;
nng_aio *aio;
enum { INIT, RECV, SEND } state;
};
void
echo(void *arg)
{
struct echo_context *ec = arg;
switch (ec->state) {
case INIT:
ec->state = RECV;
nng_ctx_recv(ec->ctx, ec->aio);
return;
case RECV:
if (nng_aio_result(ec->aio) != 0) {
// ... handle error
}
// We reuse the message on the ec->aio
ec->state = SEND;
nng_ctx_send(ec->ctx, ec->aio);
return;
case SEND:
if (nng_aio_result(ec->aio) != 0) {
// ... handle error
}
ec->state = RECV;
nng_ctx_recv(ec->ctx, ec->aio);
return;
}
}
Given the above fragment, the following example shows setting up the service. It assumes that the socket has already been created and any transports set up as well with functions such as nng_dial() or nng_listen().
#define CONCURRENCY 1024
static struct echo_context ecs[CONCURRENCY];
void
start_echo_service(nng_socket rep_socket)
{
for (int i = 0; i < CONCURRENCY; i++) {
// error checks elided for clarity
nng_ctx_open(&ecs[i].ctx, rep_socket);
nng_aio_alloc(&ecs[i].aio, echo, ecs+i);
ecs[i].state = INIT;
echo(ecs+i); // start it running
}
}
β¨ SEE ALSO β¨
bestie go read these too, they're all connected π¦:
libnng(3)nng_ctx_close(3)nng_ctx_open(3)nng_ctx_get(3)nng_ctx_id(3)nng_ctx_recv(3)nng_ctx_recvmsg(3)nng_ctx_send(3)nng_ctx_sendmsg(3)nng_ctx_set(3)nng_dialer(5)nng_listener(5)nng_socket(5)nng_options(5)nng(7)
okay that's the whole page, you ate it up π
this was the NNG Reference Manual, dated 2026-06-30, and the source is NNG_CTX(5). go forth and be concurrent, main character. πππ
π¦ where this page comes from
- ubuntu stonking: libnng-dev 1.12.0-1 Β· MIT OR Apache-2.0
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms