Messages
Messages in Scalability Protocols are the fundamental unit of transmission and reception, as these protocols are fundamentally message-oriented.
Messages have a body, containing the application-supplied payload, and a header, containing protocol specific routing and similar related information.
tip
Only applications using raw mode need to access the message header. Very few NNG applications do this.
Message Structure
typedef struct nng_msg nng_msg;
The nng_msg
structure represents a single message. It carries a body
and a header.
Create a Message
int nng_msg_alloc(nng_msg **msgp, size_t size);
The nng_msg_alloc
function allocates a new message.
It takes a size argument, and returns a message
with a preallocated body of that size in the msgp parameter.
If it succeeds, it returns zero, otherwise this function may return NNG_ENOMEM
,
indicating that insufficient memory is available to allocate a new message.
Destroy a Message
void nng_msg_free(nng_msg *msg);
The nng_msg_free
function deallocates a message.
Duplicate a Message
int nng_msg_dup(nng_msg **dup, nng_msg *msg);
The nng_msg_dup
function duplicates the message msg, storing a pointer
to the new duplicate in dup. This function also returns zero on succes, or NNG_ENOMEM
if memory is exhausted.
Message Size and Capacity
size_t nng_msg_capacity(nng_msg *msg);
int nng_msg_realloc(nng_msg *msg, size_t size);
int nng_msg_reserve(nng_msg *msg, size_t capacity);
Messages have a certain amount of pre-reserved space, which may exceed the total size of the message. This allows for content to be added to the message later, without necessarily performing a reallocation.
The nng_msg_capacity
function returns the amount of prereserved space.
If a message size change is required, and the new size will fit within the capacity
reported by this function, then change will be done without a reallocation, and
likely without a data copy as well.
tip
The capacity reported by nng_msg_capacity
may not include reserved headroom, which
is present to allow a very limited amount of content to be inserted in front of the
message without requiring the rest of the message to be copied.
The message size may be changed by use of the nng_msg_realloc
function. This
function will reallocate the underlying memory for the message msg,
preserving contents while doing so.
If the new size is smaller than the original message, it will
truncate the message, but not perform any allocations.
If reallocation fails due to insufficient memory, then the original is left intact.
The nng_msg_reserve
function ensures that the total message capacity
is at least capacity bytes. Use of this function to ensure the total anticipated
capacity is present in the message may help prevent many small allocations.
Both nng_msg_realloc
and nng_msg_reserve
return zero on success, or may return
NNG_ENOMEM
if insufficient memory exists to preform allocation.
important
Any pointers to message content obtained before a call to nng_msg_realloc
or
nng_msg_reserve
(or any other function that changes the message size) should be
treated as invalid, as the locations pointed to may be deallocated by these functions.
Message Body
void *nng_msg_body(nng_msg *msg);
size_t nng_msg_len(nng_msg *msg);
The body and body length of msg are returned by nng_msg_body
and
nng_msg_len
, respectively.
Clear the Body
void *nng_msg_clear(nng_msg *msg);
The nng_msg_clear
simply resets the total message body length to zero, but does
not affect the capacity. It does not change the underlying bytes of the message.
Add to Body
int nng_msg_append(nng_msg *msg, const void *val, size_t size);
int nng_msg_append_u16(nng_msg *msg, uint16_t val16);
int nng_msg_append_u32(nng_msg *msg, uint32_t val32);
int nng_msg_append_u64(nng_msg *msg, uint64_t val64);
int nng_msg_insert(nng_msg *msg, const void *val, size_t size);
int nng_msg_insert_u16(nng_msg *msg, uint16_t val16);
int nng_msg_insert_u32(nng_msg *msg, uint32_t val32);
int nng_msg_insert_u64(nng_msg *msg, uint64_t val64);
Appending data to a message body is done by using the nng_msg_append
functions.
The base nng_msg_append
function appends size bytes of untyped data to the end of the
message.
Use of the typed versions, ending in suffixes _u16
, _u32
, and _u64
allows
for unsigned integers to be appended directly. The integers are encoded in network byte order, with
the most significant byte appearing first. The message body will by two, four, or eight
bytes accordingly.
Data may inserted before the rest of the message body by using the nng_msg_insert
functions.
This will attempt to use “headroom” in the message to avoid a data copy.
Otherwise they are like the nng_msg_append
functions except that the put the data in front
of the messages instead of at the end.
tip
Message headroom is limited, so nng_msg_insert
is best used sparingly.
It is much more efficient to build the message content from start to end
using nng_msg_append
.
Consume From Body
int nng_msg_chop(nng_msg *msg, size_t size);
int nng_msg_chop_u16(nng_msg *msg, uint16_t *val16);
int nng_msg_chop_u32(nng_msg *msg, uint32_t *val32);
int nng_msg_chop_u64(nng_msg *msg, uint64_t *val64);
int nng_msg_trim(nng_msg *msg, size_t size);
int nng_msg_trim_u16(nng_msg *msg, uint16_t *val16);
int nng_msg_trim_u32(nng_msg *msg, uint32_t *val32);
int nng_msg_trim_u64(nng_msg *msg, uint64_t *val64);
The nng_msg_chop
functions remove data from the end of the body of message msg,
reducing the message length by either size, or the appropriate value size.
The nng_msg_trim
functions remove data from the beginning of the message body of msg.
but are otherwise just like the nng_msg_chop
functions.
If the message is not big enough to remove requisite amount of bytes, these functions
return NNG_EINVAL
. Otherwise they return zero.
Additionally, functions with typed suffixes (_u16
, _u32
, _u64
) decode the data and return it
through the appropriate val pointer.
The data is assumed to have been in network byte order in the message, but is returned in
the native machine byte order. The appropriate number of bytes is consumed for each of these types,
so two bytes for _u16
, four bytes for _u32
, and eight bytes for _u64
.
Message Header
void *nng_msg_header(nng_msg *msg);
size_t nng_msg_header_len(nng_msg *msg);
The header and header length of msg are returned by nng_msg_header
and
nng_msg_header_len
, respectively.
The message headers are generally intended for limited use, to store protocol headers.
important
The message headers are for protocol and transport headers, and not for general application payloads. Misuse of the header may prevent the application from functioning properly.
Clear the Header
void *nng_msg_header_clear(nng_msg *msg);
The nng_msg_header_clear
simply resets the total message header length to zero.
Append or Insert Header
Appending data to a message header is done by using the nng_msg_header_append
functions,
and inserting data in the header is done using the nng_msg_header_insert
functions.
These functions act just like the nng_msg_append
and nng_msg_insert
functions,
except that they operate on the message header rather than the message body.
Consume from Header
The nng_msg_header_trim
functions remove data from the beginning of the message header,
and the nng_msg_header_chop
functions remove data from the end of the message header.
These functions act just like the nng_msg_trim
and nng_msg_chop
functions,
except that they operate the message header rather than the message body.
Message Pipe
nng_pipe nng_msg_get_pipe(nng_msg *msg);
void nng_msg_get_pipe(nng_msg *msg, nng_pipe p);
The nng_msg_set_pipe
function sets the pipe associated with msg to p.
This is most often useful when used with protocols that support directing
a message to a specific peer.
For example the PAIR version 1 protocol can do
this when NNG_OPT_PAIR1_POLY
mode is set.
The nng_msg_get_pipe
function returns the pipe that was previously set on the message m,
either directly by the application, or when the message was received by the protocol.
note
Not all protocols support overriding the destination pipe.
Examples
Example 1: Preparing a message for use
#include <nng/nng.h>
nng_msg *m;
if (nng_msg_alloc(&m, strlen("content") + 1) != 0) {
// handle error
}
strcpy(nng_msg_body(m), "content");
Example 2: Preallocating message content
if (nng_msg_alloc(&m, 1024) != 0) {
// handle error
}
while ((val64 = next_datum()) != 0) P
if (nng_msg_append_u64(m, val64) != 0) {
// handle error
}
}