한국어 | English
Socket Index | Previous: Socket Overview | Next: PUB
Socket — PAIR¶
What this chapter defines — The exclusive 1:1 connection behavior and public contract of a PAIR socket.
1. PAIR overview¶
PAIR is a bidirectional socket type in which two socket instances form an exclusive 1:1 connection and both sides send and receive messages. Because there is exactly one peer—the socket at the other end of the connection—there is no input for selecting a destination peer, and a received record has no source routing ID. PAIR has no type-specific options.
This document defines only the PAIR-specific contract: how the whole-message send and receive functions behave with PAIR, the asynchronous send rules for admission—the decision to accept a send request into the Core send queue—and the absence of receive-flow state. It does not redefine contracts shared by all socket types.
The following documents own the related contracts.
| Related contract | Defining document |
|---|---|
| socket creation, common options, send/recv flags, and result enums | Socket Common |
| send ownership, completion reservation bounds, and pull completion | Socket Common |
| message lifecycle, ownership, and multipart | Message |
| result-to-errno mapping | Errors |
2. Whole-message sends and record atomicity¶
A PAIR socket passes a parts_ array and part_count_ to one zlink_send() call to submit one
record. The part order of a multipart message is the array order.
A single-part message uses an array of length one.
Record atomicity, input-slot consumption, and complete-record resubmission after failure follow Socket Common whole-message send.
%%{init: {'sequence': {'actorFontSize': '18px', 'messageFontSize': '18px', 'noteFontSize': '18px', 'boxMargin': 8, 'width': 140}, 'themeVariables': {'fontSize': '18px'}}}%%
sequenceDiagram
participant App as Application
participant Core as Core
App->>Core: zlink_send(parts, part_count, flags)
alt Record admission succeeds
Core-->>App: ZLINK_SUBMIT_OK
Note over Core: Submit the complete record as one unit
else Record admission fails
Core-->>App: Submit error
Note over Core: The peer sees no part of the record
end
PAIR receive uses zlink_recv to receive a complete
record in one call. Because there is exactly one peer, the source routing ID is NULL. Ownership,
close, capacity, and record-atomicity rules are owned by Socket Common.
3. Receive flow state¶
Socket Common defines the receive-flow state and constants that DEALER and ROUTER sockets use to notify a peer to pause or resume receiving.
PAIR is not a socket type that supports receive flow.
zlink_socket_set_receive_flow_state() returns ZLINK_CONFIG_NOT_SUPPORTED with errno == ENOTSUP
for a PAIR socket and changes nothing. The byte HWM (the byte limit retained
by a queue), low water mark, and transport backpressure (restriction
on additional submissions by the sender) owned by Socket Common remain in effect. A
PAIR socket's monitor does not report receive-flow state —
§5 ("Absence of receive flow state")
lists the observable detail.
4. Functions¶
zlink_send¶
Sends one message record.
ZLINK_EXPORT zlink_submit_result_t zlink_send (
void *s_, zlink_msg_t *parts_, size_t part_count_,
zlink_send_flags_t flags_, void *user_context_,
zlink_completion_id_t *completion_id_out_);
The parts_ array and part_count_ form the record. This function consumes every input slot on both
success and failure. Retain a copy of the complete record before the call if it may be needed again.
part_count_ == 0 returns ZLINK_SUBMIT_INVALID_ARGUMENT with EINVAL. Pass
ZLINK_SEND_FLAGS_NONE or ZLINK_SEND_FLAGS_DONTWAIT in flags_. NONE snapshots SNDTIMEO on
entry and waits through local queue admission; DONTWAIT does not wait. Socket Common
owns the exact optional ID-output and context rules.
Returns: ZLINK_SUBMIT_OK on success; otherwise a zlink_submit_result_t value that identifies
the cause. The full mapping follows the errno map.
See also: zlink_recv, zlink_completion_recv
zlink_recv¶
Receives one message record.
ZLINK_EXPORT zlink_recv_result_t zlink_recv (
void *s_,
const zlink_routing_id_t **source_rid_out_,
zlink_msg_t *parts_out_,
size_t parts_capacity_,
size_t *part_count_out_,
zlink_recv_flags_t flags_);
parts_out_ and part_count_out_ are required, and the array slots need not be initialized.
source_rid_out_ is optional and receives NULL on success. On success, ownership of the leading
*part_count_out_ slots transfers to the caller, which closes them exactly once with
zlink_multipart_close(parts_out_, *part_count_out_).
If parts_capacity_ is smaller than the record's 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. Retrying with a large enough array receives the same record. A
ZLINK_RECV_FLAGS_DONTWAIT call with no available record returns ZLINK_RECV_NO_DATA with EAGAIN.
Returns: ZLINK_RECV_OK on success; otherwise a zlink_recv_result_t value.
See also: zlink_send, zlink_msg_close
PAIR logical route and reconnect¶
The PAIR SEND target is the single logical route even when its physical pipe changes. Pipe attach after reconnect is a wake edge for that route’s wait token. SEND results, WRITABLE resubmission, token lifetime, and replay prohibition follow Socket Common whole-message send.
5. Implementation and contract-test verification requirements¶
Verify the following using only the public surface (zlink_send, zlink_recv,
zlink_completion_recv, zlink_socket_set_receive_flow_state, monitor observations, return values,
and errno). Each item maps to one test.
1:1 send and receive
- Both connected PAIR sockets can send with zlink_send and receive with zlink_recv.
- When zlink_recv succeeds, a caller that provides source_rid_out_ receives NULL.
- After a successful receive, the caller owns the leading *part_count_out_ slots and closes them exactly once with zlink_multipart_close. A failure does not transfer slot ownership.
- If parts_capacity_ is smaller than the record's part count, the call returns ZLINK_RECV_BUFFER_TOO_SMALL with ENOBUFS and the needed count without consuming the record; retrying with a large enough array receives the same record.
Whole-message send and ownership - PAIR SEND result, record atomicity, input consumption, and WRITABLE resubmission verification refer to Socket Common whole-message send.
Logical reconnect and completion
- If the connection disconnects while a wait token is live and the same PAIR logical route reconnects, the pipe attach publishes the WRITABLE record for that token, and the disconnect alone does not produce a TERMINAL record.
- A NONE send waits for reconnect of the same logical route within the snapshotted SNDTIMEO; expiration returns ZLINK_SUBMIT_BACKPRESSURED with EAGAIN, ID 0, and no completion.
- Disconnecting and reconnecting after ID 0 does not replay the same application record; the retransmission after a WRITABLE record is a record the application submitted again.
- Removing the endpoint with zlink_disconnect() ends the token with a WRITABLE record carrying ZLINK_SEND_NOT_FOUND and ENOENT. After socket close no record for that token can be received — close ends the token internally and delivers no record.
Absence of receive flow state
- zlink_socket_set_receive_flow_state() returns ZLINK_CONFIG_NOT_SUPPORTED with errno == ENOTSUP for a PAIR socket, while byte HWM, low water mark, and transport backpressure behavior remain in effect.
- A PAIR socket's monitor status does not set ZLINK_MONITOR_STATUS_DETAIL_FLOW_STATE.
- A PAIR socket does not emit ZLINK_EVENT_SEND_FLOW_PAUSED, ZLINK_EVENT_SEND_FLOW_RESUMED, or ZLINK_EVENT_FLOW_STATE_STALE events.
Socket Common owns verification of ownership transfer, completion reservation bounds, close, and pull completion.