git-subtree-dir: external/nng git-subtree-split: 29b73962b939a6fbbf6ea8d5d7680bb06d0eeb99
176 lines
5.6 KiB
Text
176 lines
5.6 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
|
|
|
|
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
|
|
|
|
[.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_recvmsg.3.adoc[nng_ctx_recvmsg(3)],
|
|
xref:nng_ctx_send.3.adoc[nng_ctx_send(3)],
|
|
xref:nng_ctx_sendmsg.3.adoc[nng_ctx_sendmsg(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)]
|