한국어 | English
03. Sockets¶
This category covers the eight socket-type interfaces (created via the IContext factories in
the Core category), their shared lifecycle/option base, and their per-type typed options. Every
socket's Send/Publish/Request/Reply returns the operation-builder family documented in the
Messaging category — this category only covers where each builder starts and what each socket
type uniquely adds. The exact signatures are owned by
Contracts/Sockets/.
ISocket / IConnectableSocket shared lifecycle¶
The base contract every socket type implements: binding, TLS, monitoring, disposal, and (for every socket except the base marker) outbound connection.
socket.Bind("tcp://*:5555");
socket.SetTlsServer(certPath, keyPath, requireClientCert: true);
using IZlinkSocket monitor = (IZlinkSocket)socket.MonitorOpen(SocketEvent.All);
socket.Close();
Options.
| Member | Default | Meaning |
|---|---|---|
Options |
— | CommonSocketOptions, below |
Bind(string address) / Unbind(string address) |
— | listen / stop listening |
MonitorOpen(SocketEvent events) |
SocketEvent.All |
opens an ISocketMonitor (Eventing category) |
SetTlsServer(certPath, keyPath, requireClientCert) |
requireClientCert = false |
apply before Bind |
SetTlsClient(caCertPath, hostname, trustSystem) |
trustSystem = false |
apply before Connect |
Close() |
— | closes the native socket immediately |
Connect(string) / Disconnect(string) / DisconnectRid(RoutingId) |
— | IConnectableSocket only — every socket type except the base IZlinkSocket marker |
Completion result. All synchronous, no return value except MonitorOpen (returns
ISocketMonitor, caller-owned). Close() closes immediately, unlike Dispose().
ISocket/IZlinkSocket are themselves IDisposable/IAsyncDisposable.
When to use. Call SetTlsServer/SetTlsClient before Bind/Connect — applying either after
the socket is already bound or connected has no effect. Call Close() only when the native socket
must release immediately rather than through normal disposal.
CommonSocketOptions¶
The typed options facade shared by every socket type, reached via socket.Options.
socket.Options.SendHighWaterMark = 100_000;
socket.Options.Linger = TimeSpan.FromSeconds(1);
socket.Options.SubmitRetryMode = SubmitRetryMode.LocalFailure;
Options.
| Member | Default | Meaning |
|---|---|---|
MaxMessageSize (long) |
-1 (no limit) | maximum size in bytes of a single accepted message |
SendHighWaterMark / ReceiveHighWaterMark (ulong) |
0 (no limit) | accounted-byte send/receive queue limit — see Core category's byte-HWM note |
SendBufferSize / ReceiveBufferSize (int) |
-1 (OS default) | OS-level socket send/receive buffer size |
Linger (TimeSpan?) |
null (wait indefinitely) | upper bound on how long Close/Dispose waits for pending sends to flush |
ReconnectInterval / ReconnectIntervalMax (TimeSpan?) |
null (disables/uncaps) | delay between reconnect attempts, and its cap |
Backlog (int) |
OS default | pending-connection queue length for a listening socket |
ReceiveTimeout / SendTimeout / ConnectTimeout / HandshakeInterval (TimeSpan?) |
null (block indefinitely / OS or native default) | upper bound on how long the matching blocking operation waits |
TcpKeepAlive (int, -1/0/1) |
OS default | OS TCP keepalive mode |
IPv6 (bool) |
false |
whether the socket accepts IPv6 connections |
TcpNoDelay (bool) |
false |
disables Nagle's algorithm when true |
Immediate (bool) |
false |
whether a send requires a live connection now, instead of queueing until one exists |
SubmitRetryMode |
Off |
whether a failed submit retries automatically on local back-pressure |
SubmitRetryTimeoutMilliseconds / SubmitRetryAttempts (int) |
mode default | retry timeout and attempt cap when SubmitRetryMode is LocalFailure |
RoutingIdDuplicatePolicy |
Reject |
what happens when a peer reuses an existing routing id |
LastEndpoint |
read-only | the concrete resolved bind address |
Completion result. Every property get/set is synchronous.
When to use. Set SendHighWaterMark/ReceiveHighWaterMark and Linger before the socket
starts exchanging messages when the defaults don't fit the deployment. Read LastEndpoint after
binding a wildcard address to learn the resolved port.
IPairSocket¶
A PAIR socket: exclusive one-to-one peering with no routing, no fields or options beyond the
shared IMessageSocket surface.
using IPairSocket pair = context.CreatePairSocket();
pair.Send().Message(Message.From("ping")).Submit();
using Received received = Received.Create();
if (pair.Recv(received)) { /* ... */ }
Options.
| Member | Default | Meaning |
|---|---|---|
Send() |
— | starts the shared SendOperation builder (Messaging category) |
Recv(Received result, RecvFlags flags) |
RecvFlags.None |
populates result |
IPairSocket adds nothing beyond this shared IMessageSocket surface.
Completion result. Recv returns bool — false only under RecvFlags.DontWait with
nothing available.
When to use. Use PAIR for an exclusive point-to-point link — it has no peer routing and does not load-balance.
IDealerSocket¶
A DEALER socket: load-balances sends across its connected peers and can issue routed requests.
using IDealerSocket dealer = context.CreateDealerSocket();
dealer.SetRoutingId(RoutingId.From("worker-3"));
IReadOnlyList<Message> reply = await dealer.Request()
.Message(Message.From("payload"))
.Async();
Options. Adds to IMessageSocket:
| Member | Default | Meaning |
|---|---|---|
Options.Probe |
— | bool, set-only; sends an empty probe on connect |
Options.RequestTimeout |
— | TimeSpan?, set-only |
Options.PeerWeight |
— | int 0-100, load-balancing weight |
SetRoutingId(RoutingId) / GetRoutingId() |
— | assigns/reads this socket's own routing id, observed by peers on connect |
Request() |
— | starts the shared RequestOperation builder; no target parameter — DEALER has no API-level peer routing id |
Completion result. Request()'s builder resolves per the Messaging category's
operation-builder entry. SetRoutingId/GetRoutingId are synchronous.
When to use. Set SetRoutingId before connecting so peers observe it from the first message.
DEALER has no protocol envelope helper to reply to an arbitrary token — reply from a received
request's context (Received.Reply(), Messaging category) or from an explicit ROUTER/service
reply surface instead.
IRouterSocket¶
A ROUTER socket: routes messages to peers addressed by routing id, and can reply to a specific peer's request.
using IRouterSocket router = context.CreateRouterSocket();
router.Send(peerRid).Message(Message.From("hello")).Submit();
router.Reply(peerRid, replyToken).Message(Message.From("ok")).Submit();
Options. Adds to IRoutedMessageSocket (Send(RoutingId), Recv(Received, RecvFlags))
and IConnectableSocket:
| Member | Default | Meaning |
|---|---|---|
Options.Mandatory |
false |
bool; error instead of silent drop on an unknown route |
Options.Handover |
false |
bool; shorthand over RoutingIdDuplicatePolicy |
Options.Probe |
— | bool |
Options.ConnectRoutingId / SetConnectRoutingId(RoutingId) |
read-only getter | assigns the next outbound connection's id instead of letting the peer choose |
Options.RequestTimeout |
— | TimeSpan? |
Options.PeerWeight |
— | int 0-100 |
SetRoutingId(RoutingId) / GetRoutingId() |
— | assigns/reads this socket's own routing id, observed by peers on connect |
Request(RoutingId peerRid) |
— | Messaging category's RequestOperation, addressed to a specific peer |
Reply(RoutingId rid, ReplyToken replyToken) |
— | Messaging category's ReplyOperation, answering the received request identified by the token |
Received.ReplyToken |
— | opaque socket-bound reply capability returned with a ROUTER request |
| request terminal | — | reply or terminal failure is returned by Request(...).Submit()/.Async(), never as application DATA |
Completion result. Request terminals settle from the socket completion queue; callers own and dispose the returned reply messages.
When to use. Request(peerRid)/Reply(rid, replyToken) for ROUTER-initiated or
ROUTER-answered request/reply, where DEALER cannot address a specific peer. Do not synthesize or
reuse the opaque token.
IPubSocket / IXPubSocket¶
PUB publishes topic-filtered messages, dropping ones with no matching subscriber; XPUB additionally surfaces subscriber subscription/unsubscription events.
using IPubSocket pub = context.CreatePubSocket();
pub.Publish("prices").Message(Message.From(tick)).Submit();
using IXPubSocket xpub = context.CreateXPubSocket();
using SubscriptionEvent evt = new SubscriptionEvent();
if (xpub.ReceiveSubscriptionEvent(evt)) { /* ... */ }
Options. Shared IPublisherSocket: Publish(string topic) (starts the synchronous
PublishOperation) and TryPublish(string topic). Publish is synchronous-only — the default PUB
contract is lossy, so a subscriber at its high-water mark has its copy dropped and the publisher
proceeds; under NoDrop the full subscriber surfaces immediately as ZlinkSubmitException.
IPubSocket also has SetRoutingId/GetRoutingId —
IXPubSocket does not (it inherits only IPublisherSocket). Both expose Options as the
same PubSocketOptions facade:
| Member | Default | Meaning |
|---|---|---|
Verbose / Verboser |
false |
deliver every (un)subscribe message, including duplicates |
Manual |
false |
subscriptions require ApproveSubscribe/RejectSubscribe instead of auto-accept |
ManualLastValue |
false |
manual mode that also replays the last cached message per topic to a newly accepted subscriber |
NoDrop |
false |
error instead of silent drop on back-pressure |
WelcomeMessage |
none | sent automatically to each newly connected subscriber; getter returns a caller-owned copy |
TopicsCount |
read-only | number of distinct topics currently subscribed by any connected peer |
ApproveSubscribe(RoutingId) / RejectSubscribe(RoutingId) |
— | require Manual |
ReceiveSubscriptionEvent(SubscriptionEvent result, RecvFlags flags) |
RecvFlags.None |
IXPubSocket only |
Completion result. ReceiveSubscriptionEvent returns bool — false only under
RecvFlags.DontWait with nothing available. ApproveSubscribe/RejectSubscribe are synchronous,
no return value.
When to use. IXPubSocket over IPubSocket specifically to observe subscriber churn via
ReceiveSubscriptionEvent, or manual admission via Manual/ApproveSubscribe/RejectSubscribe;
otherwise the two behave the same for publishing.
ISubSocket / IXSubSocket¶
SUB subscribes to topics with subscriptions set as socket options; XSUB carries its subscriptions as messages instead.
using ISubSocket sub = context.CreateSubSocket();
sub.SetSubscription("prices.");
using TopicMessage msg = new TopicMessage();
if (sub.Subscribe(msg)) { /* ... */ }
Options. Shared ISubscriberSocket:
| Member | Default | Meaning |
|---|---|---|
SetSubscription(string) / UnsetSubscription(string) |
— | adds/removes a topic filter; subscriptions accumulate |
SubscriptionAt(int index) |
SubscriptionEntry? |
the filter at that index, null when out of range |
Subscribe(TopicMessage result, RecvFlags flags) |
RecvFlags.None |
populates result with the next matching publish |
Options.TopicsCount (int) |
read-only | number of active subscription filters |
SetRoutingId(RoutingId) / GetRoutingId() |
— | assigns/reads this socket's own routing id; ISubSocket only |
IXSubSocket adds nothing beyond ISubscriberSocket — no SetRoutingId/GetRoutingId, no
unique members; every operation is the shared surface (its own Options is the same
SubSocketOptions type).
Completion result. Subscribe returns bool — false only under RecvFlags.DontWait with
nothing available.
When to use. ISubSocket for the common case (subscriptions as socket options); IXSubSocket
specifically when subscriptions must be carried as ordinary messages instead.
IStreamSocket¶
A STREAM socket: exchanges framed packets directly with raw TCP peers, outside the zlink wire protocol used by every other socket type.
using IStreamSocket stream = context.CreateStreamSocket();
stream.Options.ReceiveMode = StreamReceiveMode.Packet;
using var packet = StreamPacket.Create();
bool ok = stream.RecvPacket(packet, RecvFlags.None);
Options. Extends IRoutedMessageSocket:
| Member | Default | Meaning |
|---|---|---|
Options.Notify |
false |
bool; deliver peer connect/disconnect as application messages |
Options.ReceiveMode |
Unspecified |
set Raw or Packet before bind/connect; immutable afterward |
Recv(Received, RecvFlags) / RecvPacket(StreamPacket, RecvFlags) |
RecvFlags.None |
pull RAW records or PACKET header/body pairs according to the selected mode |
DisconnectRid(RoutingId peerRid) |
— | disconnects the peer identified by that routing id |
Completion result. Both receive forms return bool; false means DONTWAIT no-data. The
caller owns the populated receive envelope or packet and disposes it.
When to use. Select RAW or PACKET before bind/connect, then call only the matching pull receive.
Socket enums¶
Shared enums referenced across every entry above.
| Enum | Used by | Values |
|---|---|---|
SocketType |
Internal socket-kind identification | Any, Pair, Pub, Sub, Dealer, Router, XPub, XSub, Stream |
AutoHwmProfile |
IContextOptions.AutoHwmProfile (Core category) |
Compact, LowLatency, Balanced, Throughput |
RidDuplicatePolicy |
CommonSocketOptions.RoutingIdDuplicatePolicy, RouterSocketOptions.Handover |
Reject, Handover |
SubmitRetryMode |
CommonSocketOptions.SubmitRetryMode |
Off, LocalFailure |
SendFlags |
Every send/request/reply builder's .Flags(...) stage (Messaging category) |
None, DontWait |
RecvFlags |
Every Recv/Subscribe/ReceiveSubscriptionEvent/RecvPart |
None, DontWait |
When to use. DontWait on either flags enum turns a blocking call into a non-blocking one that
reports false/back-pressure instead of blocking.
See Contracts/Sockets/ and the
.NET binding spec for the full rationale.