한국어 | English
Socket Index | Previous: PUB | Next: XPUB
Socket — SUB¶
What this chapter defines — the subscription behavior and public contract of a SUB socket.
1. SUB socket overview¶
SUB is a receive-only socket type that uses topic filtering to receive only subscribed messages. A topic is a sequence of classification bytes carried with a message, and SUB receives a message when its topic matches a registered subscription filter. SUB receives data only—PUB and XPUB publish it. Subscription management, such as registering and removing subscriptions, uses control-plane calls that configure and control the socket rather than the data plane that carries messages.
This document defines the SUB-specific contract: registering and removing subscription filters,
filter matching rules, SUB-specific options (zlink_sub_option_t), the topic-and-payload receive function,
and subscription inventory queries. These functions also apply to raw XSUB; XSUB
defines XSUB-specific behavior.
The following documents own the related contracts.
| Related contract | Defining document |
|---|---|
Common socket options (including RCVHWM and RCVBUF), lifetime, thread safety, and receive model |
Socket Common |
| Sockets that publish subscription messages and topic wire rules | PUB, XPUB |
| Auto HWM budget calculation and admission | Auto HWM |
| Message lifecycle and ownership | Message |
2. Subscriptions and filter matching¶
Subscriptions are managed by filter string.
- Register —
zlink_set_subscriptionregisters one filter as a subscription. The bytes before the terminating NUL form a byte prefix, and a message matches when its topic starts with those bytes. An empty string subscribes to every message. There is no wildcard syntax. - Remove —
zlink_unset_subscriptionremoves a previously registered subscription using the same byte-prefix interpretation. - Query — Read the number of subscribed topics through the read-only
ZLINK_SUB_OPT_TOPICS_COUNToption, and read an individual filter by index throughzlink_subscription_at. - Receive — Receive the topic and complete payload record of a matching message through
zlink_subscribe.
3. Automatic HWM defaults¶
Unless the application sets it directly, the context Auto HWM budget policy automatically calculates the byte limit (HWM) retained by the SUB receive queue.
SUB is classified as the recv_ingress role by the context Auto HWM policy. The active
Auto HWM profile selects the Core memory-budget ratio and the per-role byte boundaries, and Core
distributes that budget among unique physical directional queues.
The default profile is balanced. If the user sets RCVHWM directly, that application direction is
excluded from automatic distribution. RCVBUF is an OS socket-buffer option and is not changed by
Auto HWM.
Auto HWM owns the exact budget-calculation and admission contract.
Socket Common owns the RCVHWM and RCVBUF options themselves.
4. Receive flow state¶
DEALER and ROUTER report receive-flow state to peers that send to them. SUB is not a socket type that supports receive flow.
zlink_socket_set_receive_flow_state()returnsZLINK_CONFIG_NOT_SUPPORTEDwitherrno == ENOTSUPfor a SUB socket and changes nothing.- The byte HWM, low water mark, and transport backpressure defined by Socket Common remain in effect.
- A SUB socket monitor does not set
ZLINK_MONITOR_STATUS_DETAIL_FLOW_STATEand does not emitZLINK_EVENT_SEND_FLOW_PAUSED,ZLINK_EVENT_SEND_FLOW_RESUMED, orZLINK_EVENT_FLOW_STATE_STALE.
5. Options (zlink_sub_option_t)¶
Use these options with zlink_set_sub_option() / zlink_get_sub_option().
typedef enum zlink_sub_option_t
{
ZLINK_SUB_OPT_TOPICS_COUNT = 0x3400 // Number of subscribed topics (int, read-only)
} zlink_sub_option_t;
6. Functions¶
zlink_set_sub_option¶
Set a SUB/XSUB-specific socket option.
ZLINK_EXPORT zlink_config_result_t zlink_set_sub_option (void *handle_,
zlink_sub_option_t option_,
const void *optval_,
size_t optvallen_);
Configures a SUB/XSUB socket option. Use zlink_set_option() for common options shared across all
socket types.
Returns: ZLINK_CONFIG_OK on success; otherwise a zlink_config_result_t value. zlink_errno() retains the detailed internal errno for diagnostics.
See also: zlink_get_sub_option, zlink_set_option
zlink_get_sub_option¶
Get a SUB/XSUB-specific socket option.
ZLINK_EXPORT zlink_config_result_t zlink_get_sub_option (void *handle_,
zlink_sub_option_t option_,
void *optval_,
size_t *optvallen_);
Retrieves the current value of a SUB/XSUB socket option.
Returns: ZLINK_CONFIG_OK on success; otherwise a zlink_config_result_t value. zlink_errno() retains the detailed internal errno for diagnostics.
See also: zlink_set_sub_option
zlink_set_subscription¶
Subscribe to a topic filter.
Subscribes to messages matching filter_. filter_ is a NUL-terminated string and cannot contain
an embedded NUL. The bytes before the terminating NUL form a byte-prefix filter, so a message
matches when its topic starts with those bytes. An empty string subscribes to every message. There
is no wildcard syntax; a trailing * is a literal byte.
Applicable types: raw SUB, raw XSUB.
Returns: ZLINK_CONFIG_OK on success; otherwise a zlink_config_result_t value. zlink_errno() retains the detailed internal errno for diagnostics.
Errors: EFAULT if handle_ is NULL. EINVAL if filter_ is NULL or the handle type does not
support subscriptions.
See also: zlink_unset_subscription, zlink_subscribe
zlink_unset_subscription¶
Unsubscribe from a topic filter.
Removes a previously registered subscription. filter_ must be a NUL-terminated string without an
embedded NUL. It uses the same byte-prefix interpretation as zlink_set_subscription(); the bytes
before the terminating NUL must match a previously registered prefix.
Applicable types: raw SUB, raw XSUB.
Returns: ZLINK_CONFIG_OK on success; otherwise a zlink_config_result_t value. zlink_errno() retains the detailed internal errno for diagnostics.
Errors: EFAULT if handle_ is NULL. EINVAL if filter_ is NULL or the handle type does not
support removing subscriptions.
See also: zlink_set_subscription
zlink_subscribe¶
Receive the topic and complete payload record from a raw SUB or XSUB socket.
ZLINK_EXPORT zlink_recv_result_t zlink_subscribe (
void *sub_,
const zlink_routing_id_t **source_rid_out_,
char *topic_id_buf_, size_t topic_id_capacity_, size_t *topic_id_len_out_,
zlink_msg_t *parts_out_, size_t parts_capacity_, size_t *part_count_out_,
zlink_recv_flags_t flags_);
topic_id_len_out_, parts_out_, and part_count_out_ are required. The array slots need not be initialized.
source_rid_out_ is optional and always receives NULL for raw SUB and XSUB. On success, the
function copies the binary topic bytes into the caller's buffer without a NUL byte and transfers
the complete payload record into the array. The caller closes the leading *part_count_out_ slots
exactly once with zlink_multipart_close.
If topic_id_capacity_ is smaller than the topic length (a zero-length topic succeeds with capacity 0), the function writes the required topic
length to *topic_id_len_out_ and returns ZLINK_RECV_BUFFER_TOO_SMALL with ENOBUFS. Core keeps
that message's topic and payload internally, leaves parts_out_ and every output other than
topic_id_len_out_ unchanged, and does not transfer ownership of the slots. Calling again with a sufficient
buffer returns the same retained message. If capacity is greater than zero but topic_id_buf_ is NULL, the
function returns ZLINK_RECV_INVALID_HANDLE with EFAULT before inspecting or consuming the queue
and leaves every output and parts_out_ unchanged.
If parts_capacity_ is smaller than the payload part count, the record is not consumed, the needed
count is written to *part_count_out_, and the call returns ZLINK_RECV_BUFFER_TOO_SMALL with
ENOBUFS. Other outputs and array slots are unchanged; retrying with a large enough array receives
the same record. Applicable types are raw SUB and raw XSUB.
zlink_subscription_at¶
Retrieve the subscription filter at a given index.
ZLINK_EXPORT zlink_config_result_t zlink_subscription_at (void *handle_,
size_t index_,
char *filter_out_,
size_t *filter_len_inout_,
int *is_pattern_out_);
index_ is a zero-based index into a snapshot taken at query time and sorted in ascending
lexicographic order by filter bytes, not registration order. On success, filter_out_ contains only
the filter bytes and has no terminating NUL. This output is therefore not a C string. On entry,
*filter_len_inout_ is the buffer size; on return, it is the filter length in bytes.
is_pattern_out_ is an optional output and may be NULL. When provided, it reports whether the
filter is a pattern subscription. All raw subscriptions are byte-prefix filters, so it receives 0.
If the buffer is too small, the function writes the required length to *filter_len_inout_ and
returns ZLINK_CONFIG_BUFFER_TOO_SMALL with errno == ENOBUFS. It writes no partial data to
filter_out_ and leaves *is_pattern_out_ unchanged. It does not consume or modify the subscription
inventory, so the caller can retry the same index_ with a sufficient buffer.
Applicable types: raw SUB, raw XSUB.
Returns: ZLINK_CONFIG_OK on success; otherwise a zlink_config_result_t value. zlink_errno() retains the detailed internal errno for diagnostics.
Errors: ENOENT if the index is out of range. ENOBUFS if the buffer is too small. ENOTSUP if
the handle type does not support subscription queries.
See also: zlink_set_subscription, zlink_get_sub_option
7. Implementation and contract test verification requirements¶
Verify the following through only the public surface: the subscription functions, SUB option set
and get, zlink_subscribe results, return values, and errno. Each item maps to one unit test.
Subscription registration and removal
- A filter registered through
zlink_set_subscriptionmatches by byte prefix—a message is received throughzlink_subscribewhen its topic begins with the filter bytes before the terminating NUL. - An empty-string filter subscribes to every message.
- A filter with a trailing
*matches*as a literal byte; it is not expanded as a wildcard. zlink_unset_subscriptionremoves the subscription whose previously registered prefix matches the filter bytes before the terminating NUL.- For
zlink_set_subscriptionandzlink_unset_subscription, a NULLhandle_producesEFAULT; a NULLfilter_or a handle type that does not support subscription registration or removal producesEINVAL.
Subscription inventory queries
- Reading the read-only
ZLINK_SUB_OPT_TOPICS_COUNTthroughzlink_get_sub_optionreturns the number of subscribed topics as anint. - The zero-based
index_forzlink_subscription_atfollows snapshot order sorted by filter bytes, not registration order. Each call takes a fresh snapshot, and that snapshot is not atomic with aZLINK_SUB_OPT_TOPICS_COUNTquery: if subscriptions change between the two calls, the sameindex_may name a different filter or fail withENOENT, so the caller serializes subscription changes while it reads the list. - On success,
filter_out_contains only the filter bytes and no terminating NUL.*filter_len_inout_is that byte length, andfilter_out_is not a C string. is_pattern_out_is an optional output and may be NULL. When provided, it receives0because every raw subscription is a byte-prefix filter.- If the buffer is too small, the function writes the required length to
*filter_len_inout_and returnsZLINK_CONFIG_BUFFER_TOO_SMALLwithENOBUFS. It writes no partial data tofilter_out_, leaves*is_pattern_out_unchanged, and allows a retry of the sameindex_with a sufficient buffer. - An out-of-range index produces
ENOENT; a handle type that does not support subscription queries producesENOTSUP.
Topic and payload-record receive
- A successful
zlink_subscribecopies the binary topic bytes into the caller's buffer without a NUL byte and fills the array with the complete payload record; the caller closes the leading*part_count_out_slots exactly once withzlink_multipart_close. - On raw SUB and XSUB,
source_rid_out_always receivesNULL. - If
topic_id_capacity_is smaller than the topic length (a zero-length topic succeeds with capacity 0), the function writes the required length to*topic_id_len_out_and returnsZLINK_RECV_BUFFER_TOO_SMALLwithENOBUFS. Core retains that message's topic and payload internally, so a retry with a sufficient buffer receives the same message;parts_out_and every output other thantopic_id_len_out_remain unchanged. - If
parts_capacity_is smaller than the payload part count, the call writes the needed count to*part_count_out_and returnsZLINK_RECV_BUFFER_TOO_SMALLwithENOBUFS. The record and other outputs remain unchanged, and retrying with a large enough array receives the same record. - A record whose topic frame is not followed by a payload part (the topic frame lacks
MORE) returnsZLINK_RECV_INTERNAL_ERRORwithEPROTO. - If capacity is greater than zero but
topic_id_buf_is NULL, the function returnsZLINK_RECV_INVALID_HANDLEwithEFAULTbefore inspecting or consuming the queue, and every output andparts_out_remains unchanged. - All payload parts of a multipart message are returned in array order in one call, with no partial-record state.
Automatic HWM defaults
- An application direction with an explicitly set
RCVHWMis excluded from automatic distribution. - Auto HWM does not change
RCVBUF.
Absence of receive flow state
- Calling
zlink_socket_set_receive_flow_state()on a SUB socket returnsZLINK_CONFIG_NOT_SUPPORTEDwithENOTSUPand changes nothing. - A SUB socket monitor does not set
ZLINK_MONITOR_STATUS_DETAIL_FLOW_STATEand does not emitZLINK_EVENT_SEND_FLOW_PAUSED,ZLINK_EVENT_SEND_FLOW_RESUMED, orZLINK_EVENT_FLOW_STATE_STALE.
Common return convention
- The functions above that return
zlink_config_result_treturnZLINK_CONFIG_OKon success and azlink_config_result_tvalue on failure.zlink_errno()retains the detailed internal errno for diagnostics.
Auto HWM §5 owns verification of Auto HWM budget calculation and admission.