한국어 | English
03. Sockets¶
이 category는 (Core category의 IContext factory로 생성되는) 8개 socket-type
interface, 이들의 공유 lifecycle/option 기반, 그리고 타입별 typed option을 다룬다.
모든 socket의 Send/Publish/Request/Reply는 Messaging category에 문서화된
operation-builder family를 반환한다 — 이 category는 각 builder가 어디서 시작하고 각
socket type이 고유하게 무엇을 더하는지만 다룬다. 정확한 signature는
Contracts/Sockets/가
소유한다.
ISocket / IConnectableSocket 공유 lifecycle¶
모든 socket type이 구현하는 기반 contract다 — binding, TLS, monitoring, disposal, 그리고 (기본 marker를 제외한 모든 socket type의) outbound connection.
socket.Bind("tcp://*:5555");
socket.SetTlsServer(certPath, keyPath, requireClientCert: true);
using IZlinkSocket monitor = (IZlinkSocket)socket.MonitorOpen(SocketEvent.All);
socket.Close();
옵션.
| Member | 기본값 | 의미 |
|---|---|---|
Options |
— | CommonSocketOptions, 아래 |
Bind(string address) / Unbind(string address) |
— | 수신 시작/중지 |
MonitorOpen(SocketEvent events) |
SocketEvent.All |
ISocketMonitor를 염(Eventing category) |
SetTlsServer(certPath, keyPath, requireClientCert) |
requireClientCert = false |
Bind 전에 적용 |
SetTlsClient(caCertPath, hostname, trustSystem) |
trustSystem = false |
Connect 전에 적용 |
Close() |
— | native socket을 즉시 닫음 |
Connect(string) / Disconnect(string) / DisconnectRid(RoutingId) |
— | IConnectableSocket만 — 기본 IZlinkSocket marker를 제외한 모든 socket type |
완료 결과. MonitorOpen을 제외한 모든 member는 반환값 없이 동기다.
MonitorOpen은 ISocketMonitor를 반환한다(caller 소유). Close()는
Dispose()와 달리 즉시 닫는다. ISocket/IZlinkSocket 자체가
IDisposable/IAsyncDisposable이다.
선택 기준. Bind/Connect 전에 각각 SetTlsServer/SetTlsClient를 호출한다 —
이미 bind·connect된 후엔 효과가 없다. native socket이 일반 disposal이 아니라 즉시
해제돼야 할 때만 Close()를 쓴다.
CommonSocketOptions¶
socket.Options로 도달하는, 모든 socket type이 공유하는 typed option facade.
socket.Options.SendHighWaterMark = 100_000;
socket.Options.Linger = TimeSpan.FromSeconds(1);
socket.Options.SubmitRetryMode = SubmitRetryMode.LocalFailure;
옵션.
| Member | 기본값 | 의미 |
|---|---|---|
MaxMessageSize(long) |
-1(제한 없음) | 단일 수신 메시지의 최대 바이트 크기 |
SendHighWaterMark / ReceiveHighWaterMark(ulong) |
0(제한 없음) | accounted-byte send/receive queue 제한 — Core category의 byte-HWM 참고 |
SendBufferSize / ReceiveBufferSize(int) |
-1(OS 기본값) | OS 레벨 socket send/receive buffer 크기 |
Linger(TimeSpan?) |
null(무기한 대기) | Close/Dispose가 대기 중인 send가 flush될 때까지 기다리는 상한 |
ReconnectInterval / ReconnectIntervalMax(TimeSpan?) |
null(비활성화/무제한) | 재연결 시도 사이 간격, 그리고 그 상한 |
Backlog(int) |
OS 기본값 | listening socket의 대기 connection queue 길이 |
ReceiveTimeout / SendTimeout / ConnectTimeout / HandshakeInterval(TimeSpan?) |
null(무기한 block / OS·native 기본값) | 대응하는 blocking operation이 기다리는 상한 |
TcpKeepAlive(int, -1/0/1) |
OS 기본값 | OS TCP keepalive 모드 |
IPv6(bool) |
false |
socket이 IPv6 connection을 받을지 |
TcpNoDelay(bool) |
false |
true면 Nagle 알고리즘을 끔 |
Immediate(bool) |
false |
send가 지금 살아있는 connection을 요구할지, 아니면 생길 때까지 대기열에 쌓을지 |
SubmitRetryMode |
Off |
local back-pressure에서 실패한 submit을 자동 재시도할지 |
SubmitRetryTimeoutMilliseconds / SubmitRetryAttempts(int) |
모드 기본값 | SubmitRetryMode가 LocalFailure일 때의 재시도 timeout과 시도 횟수 상한 |
RoutingIdDuplicatePolicy |
Reject |
peer가 기존 routing id를 재사용하면 어떻게 되는지 |
LastEndpoint |
읽기 전용 | 실제로 resolve된 bind 주소 |
완료 결과. 모든 property get/set은 동기다.
선택 기준. 기본값이 배포 환경에 맞지 않을 때 socket이 메시지 교환을 시작하기 전에
SendHighWaterMark/ReceiveHighWaterMark, Linger를 설정한다. wildcard 주소로
bind한 후 resolve된 포트를 알려면 LastEndpoint를 읽는다.
IPairSocket¶
PAIR socket — 배타적 1:1 peering이며 라우팅이 없고, 공유 IMessageSocket 표면 외에
필드나 옵션이 없다.
using IPairSocket pair = context.CreatePairSocket();
pair.Send().Message(Message.From("ping")).Submit();
using Received received = Received.Create();
if (pair.Recv(received)) { /* ... */ }
옵션.
| Member | 기본값 | 의미 |
|---|---|---|
Send() |
— | 공유 SendOperation builder 시작(Messaging category) |
Recv(Received result, RecvFlags flags) |
RecvFlags.None |
result를 채움 |
IPairSocket은 이 공유 IMessageSocket 표면 외에 더하는 게 없다.
완료 결과. Recv는 bool을 반환한다 — RecvFlags.DontWait에서 아무것도 없을
때만 false다.
선택 기준. 배타적 point-to-point 링크엔 PAIR를 쓴다 — peer 라우팅이 없고 load-balance하지 않는다.
IDealerSocket¶
DEALER socket — 연결된 peer 전체에 send를 load-balance하고 routed request를 낼 수 있다.
using IDealerSocket dealer = context.CreateDealerSocket();
dealer.SetRoutingId(RoutingId.From("worker-3"));
IReadOnlyList<Message> reply = await dealer.Request()
.Message(Message.From("payload"))
.Async();
옵션. IMessageSocket에 더하는 것:
| Member | 기본값 | 의미 |
|---|---|---|
Options.Probe |
— | bool, set-only; connect 시 빈 probe 전송 |
Options.RequestTimeout |
— | TimeSpan?, set-only |
Options.PeerWeight |
— | int 0-100, load-balancing 가중치 |
SetRoutingId(RoutingId) / GetRoutingId() |
— | 이 socket 자신의 routing id를 지정/읽음, peer가 connect 시 관찰 |
Request() |
— | 공유 RequestOperation builder 시작; target 인자 없음 — DEALER는 API 레벨 peer routing id가 없음 |
완료 결과. Request()의 builder는 Messaging category의 operation-builder
항목대로 resolve된다. SetRoutingId/GetRoutingId는 동기다.
선택 기준. peer가 첫 메시지부터 관찰하도록 connect 전에 SetRoutingId를
설정한다. DEALER엔 임의 token에 reply하는 protocol envelope helper가 없다 —
수신된 request context(Received.Reply(), Messaging category)에서 답하거나 명시적
ROUTER/service reply 표면을 쓴다.
IRouterSocket¶
ROUTER socket — routing id로 지정된 peer에게 메시지를 보내고, 특정 peer의 request에 reply할 수 있다.
using IRouterSocket router = context.CreateRouterSocket();
router.Send(peerRid).Message(Message.From("hello")).Submit();
router.Reply(peerRid, replyToken).Message(Message.From("ok")).Submit();
옵션. IRoutedMessageSocket(Send(RoutingId), Recv(Received, RecvFlags))과
IConnectableSocket에 더하는 것:
| Member | 기본값 | 의미 |
|---|---|---|
Options.Mandatory |
false |
bool; 알 수 없는 route로의 send를 조용히 버리는 대신 에러 |
Options.Handover |
false |
bool; RoutingIdDuplicatePolicy의 shorthand |
Options.Probe |
— | bool |
Options.ConnectRoutingId / SetConnectRoutingId(RoutingId) |
읽기 전용 getter | peer가 고르는 대신 다음 outbound connection의 id를 지정 |
Options.RequestTimeout |
— | TimeSpan? |
Options.PeerWeight |
— | int 0-100 |
SetRoutingId(RoutingId) / GetRoutingId() |
— | 이 socket 자신의 routing id를 지정/읽음, peer가 connect 시 관찰 |
Request(RoutingId peerRid) |
— | Messaging category의 RequestOperation, 특정 peer로 향함 |
Reply(RoutingId rid, ReplyToken replyToken) |
— | token이 식별하는 수신 request에 답하는 ReplyOperation |
Received.ReplyToken |
— | ROUTER request와 함께 반환되는 opaque socket-bound reply capability |
| request terminal | — | reply 또는 terminal failure는 application DATA가 아니라 Request(...).Submit()/.Async() 결과 |
완료 결과. Request terminal은 socket completion queue에서 settle되며 caller가 반환된 reply message를 소유하고 dispose한다.
선택 기준. DEALER가 특정 peer를 지정할 수 없는 ROUTER 주도·ROUTER 응답
request/reply엔 Request(peerRid)/Reply(rid, replyToken)을 쓴다. Opaque token은 합성하거나
재사용하지 않는다.
IPubSocket / IXPubSocket¶
PUB는 매칭되는 구독자가 없으면 버리는 topic-filtered 메시지를 publish하고, XPUB는 추가로 구독자의 subscribe/unsubscribe event를 노출한다.
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)) { /* ... */ }
옵션. 공유 IPublisherSocket: Publish(string topic)(동기 PublishOperation
시작)과 TryPublish(string topic). publish는 동기 전용이다 — 기본 PUB 계약은
lossy이므로 HWM에 도달한 subscriber의 copy는 drop되고 publisher는 즉시
진행하며, NoDrop에서는 가득 찬 subscriber가 그 자리에서
ZlinkSubmitException으로 표면화된다. IPubSocket은 SetRoutingId/GetRoutingId도
있다 — IXPubSocket은 없다(IPublisherSocket만 상속). 둘 다 같은
PubSocketOptions facade를 Options로 노출한다:
| Member | 기본값 | 의미 |
|---|---|---|
Verbose / Verboser |
false |
중복 포함 모든 (un)subscribe 메시지 전달 |
Manual |
false |
구독이 auto-accept 대신 ApproveSubscribe/RejectSubscribe 요구 |
ManualLastValue |
false |
새로 승인된 구독자에게 topic별 마지막 캐시 메시지도 재생하는 manual 모드 |
NoDrop |
false |
back-pressure에서 조용히 버리는 대신 에러 |
WelcomeMessage |
없음 | 새로 연결된 구독자마다 자동 전송; getter는 caller 소유 복사본 반환 |
TopicsCount |
읽기 전용 | 연결된 peer 중 하나라도 구독 중인 고유 topic 개수 |
ApproveSubscribe(RoutingId) / RejectSubscribe(RoutingId) |
— | Manual 필요 |
ReceiveSubscriptionEvent(SubscriptionEvent result, RecvFlags flags) |
RecvFlags.None |
IXPubSocket만 |
완료 결과. ReceiveSubscriptionEvent는 bool을 반환한다 —
RecvFlags.DontWait에서 아무것도 없을 때만 false다. ApproveSubscribe/
RejectSubscribe는 반환값 없이 동기다.
선택 기준. ReceiveSubscriptionEvent로 구독자 변동을 관찰하려면(또는
Manual/ApproveSubscribe/RejectSubscribe로 수동 admission을 하려면)
IPubSocket 대신 IXPubSocket을 쓴다 — publish 자체는 둘이 같게 동작한다.
ISubSocket / IXSubSocket¶
SUB는 구독을 socket option으로 설정하는 방식으로 topic을 구독하고, XSUB는 대신 구독을 메시지로 실어 나른다.
using ISubSocket sub = context.CreateSubSocket();
sub.SetSubscription("prices.");
using TopicMessage msg = new TopicMessage();
if (sub.Subscribe(msg)) { /* ... */ }
옵션. 공유 ISubscriberSocket:
| Member | 기본값 | 의미 |
|---|---|---|
SetSubscription(string) / UnsetSubscription(string) |
— | topic filter를 추가/제거; 구독은 누적된다 |
SubscriptionAt(int index) |
SubscriptionEntry? |
해당 index의 filter, 범위 밖이면 null |
Subscribe(TopicMessage result, RecvFlags flags) |
RecvFlags.None |
다음 매칭 publish로 result를 채움 |
Options.TopicsCount(int) |
읽기 전용 | 활성 구독 filter 개수 |
SetRoutingId(RoutingId) / GetRoutingId() |
— | 이 socket 자신의 routing id를 지정/읽음; ISubSocket만 |
IXSubSocket은 ISubscriberSocket 외에 더하는 게 없다 — SetRoutingId/
GetRoutingId도, 고유 member도 없다; 모든 operation이 공유 표면이다(자신의
Options도 같은 SubSocketOptions 타입).
완료 결과. Subscribe는 bool을 반환한다 — RecvFlags.DontWait에서 아무것도
없을 때만 false다.
선택 기준. 일반적인 경우(구독을 socket option으로 설정)엔 ISubSocket을,
구독을 일반 메시지로 실어 날라야 할 때만 IXSubSocket을 쓴다.
IStreamSocket¶
STREAM socket — 다른 모든 socket type이 쓰는 zlink wire protocol 밖에서, raw TCP peer와 framed packet을 직접 주고받는다.
using IStreamSocket stream = context.CreateStreamSocket();
stream.Options.ReceiveMode = StreamReceiveMode.Packet;
using var packet = StreamPacket.Create();
bool ok = stream.RecvPacket(packet, RecvFlags.None);
옵션. IRoutedMessageSocket을 확장:
| Member | 기본값 | 의미 |
|---|---|---|
Options.Notify |
false |
bool; peer connect/disconnect를 application message로 전달 |
Options.ReceiveMode |
Unspecified |
bind/connect 전에 Raw 또는 Packet 설정, 이후 immutable |
Recv(Received, RecvFlags) / RecvPacket(StreamPacket, RecvFlags) |
RecvFlags.None |
선택한 모드에 따라 RAW record 또는 PACKET header/body pair pull |
DisconnectRid(RoutingId peerRid) |
— | 그 routing id로 식별되는 peer의 connection을 끊음 |
완료 결과. 두 receive 형식 모두 bool을 반환하며 false는 DONTWAIT no-data다.
Caller가 채워진 receive envelope 또는 packet을 소유하고 dispose한다.
선택 기준. Bind/connect 전에 RAW 또는 PACKET을 고르고 일치하는 pull receive만 호출한다.
Socket enum¶
위 모든 항목에서 참조하는 공유 enum.
| Enum | 사용처 | 값 |
|---|---|---|
SocketType |
내부 socket 종류 식별 | 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 |
모든 send/request/reply builder의 .Flags(...) 단계(Messaging category) |
None, DontWait |
RecvFlags |
모든 Recv/Subscribe/ReceiveSubscriptionEvent/RecvPart |
None, DontWait |
선택 기준. 두 flags enum 어느 쪽이든 DontWait는 blocking 호출을
non-blocking으로 바꿔 block하는 대신 false/back-pressure를 보고한다.
Contracts/Sockets/와
.NET 바인딩 스펙에서 전체 근거를 확인한다.