doompanning/docs/man/nng_ctx.5.adoc
oxmox 17f68cf8fe Squashed 'external/nng/' content from commit 169221da
git-subtree-dir: external/nng
git-subtree-split: 169221da8d53b2ca4fda76f894bee8505887a7c6
2023-02-03 21:18:59 +01:00

174 lines
5.5 KiB
Text

= nng_ctx(5)
//
// Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
//
// This document is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
// file was obtained (LICENSE.txt). A copy of the license may also be
// found online at https://opensource.org/licenses/MIT.
//
== NAME
nng_ctx - protocol context
== SYNOPSIS
[source, c]
----
#include <nng/nng.h>
typedef struct nng_ctx_s nng_ctx
----
== DESCRIPTION
An `nng_ctx`(((context))) is a handle to an underlying context object,
which keeps the protocol state for some stateful protocols.
The purpose of a separate context object is to permit applications to
share a single socket, with its various underlying
xref:nng_dialer.5.adoc[dialers],
xref:nng_listener.5.adoc[listeners],
and xref:nng_pipe.5.adoc[pipes],
while still benefiting from separate state tracking.
For example, a xref:nng_req.7.adoc[_req_] context will contain the request ID
of any sent request, a timer to retry the request on failure, and so forth.
A separate context on the same socket can have similar data, but corresponding
to a completely different request.
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.
All contexts share the same socket, and so some options, as well as the
underlying transport details, will be common to all contexts on that socket.
NOTE: Not every protocol supports separate contexts.
See the protocol-specific documentation for further details about whether
contexts are supported, and details about what options are supported for
contexts.
Protocols that make use of contexts will also have a default context
that is 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.
(((concurrent)))(((raw mode)))
Historically, applications wanting to use a stateful protocol concurrently
would have to resort to xref:nng.7.adoc#raw_mode[raw mode] sockets, which bypasses
much of the various protocol handling, leaving it to up to the application
to do so.
Contexts make it possible to still benefit from advanced protocol handling,
including timeouts, retries, and matching requests to responses, while doing so
concurrently.
NOTE: xref:nng.7.adoc#raw_mode[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
xref:nng.7.adoc#raw_mode[raw mode] sockets when possible.
IMPORTANT: Use of file descriptor polling (with descriptors
obtained using the
xref:nng_options.5.adoc#NNG_OPT_RECVFD[`NNG_OPT_RECVFD`] or
xref:nng_options.5.adoc#NNG_OPT_SENDFD[`NNG_OPT_SENDFD`] options) 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.
[[NNG_CTX_INITIALIZER]]
=== Initialization
A context may be initialized using the macro `NNG_CTX_INITIALIZER`
before it is opened, to prevent confusion with valid open contexts.
== EXAMPLE
The following program fragment demonstrates the use of contexts to implement
a concurrent xref:nng_rep.7.adoc[_rep_] service that simply echos messages back
to the sender.
[source, c]
----
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 xref:nng_socket.5.adoc[socket] has already been
created and any transports set up as well with functions such as
xref:nng_dial.3.adoc[`nng_dial()`]
or xref:nng_listen.3.adoc[`nng_listen()`].
[source,c]
----
#define CONCURRENCY 1024
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(ec[i].ctx, rep_socket)
nng_aio_alloc(ec[i].aio, echo, &e[i]);
ec[i].state = INIT;
echo(&ec[i]); // start it running
}
}
----
== SEE ALSO
[.text-left]
xref:libnng.3.adoc[libnng(3)],
xref:nng_ctx_close.3.adoc[nng_ctx_close(3)],
xref:nng_ctx_open.3.adoc[nng_ctx_open(3)],
xref:nng_ctx_get.3.adoc[nng_ctx_get(3)],
xref:nng_ctx_id.3.adoc[nng_ctx_id(3)],
xref:nng_ctx_recv.3.adoc[nng_ctx_recv(3)],
xref:nng_ctx_send.3.adoc[nng_ctx_send(3)],
xref:nng_ctx_set.3.adoc[nng_ctx_set(3)],
xref:nng_dialer.5.adoc[nng_dialer(5)],
xref:nng_listener.5.adoc[nng_listener(5)],
xref:nng_socket.5.adoc[nng_socket(5)],
xref:nng_options.5.adoc[nng_options(5)],
xref:nng.7.adoc[nng(7)]