한국어 | English
03. Sockets¶
이 category는 Socket/ConnectableSocket(공유 기반 interface),
CommonSocketOptions와 타입별 확장, 8개 구체 socket interface, 공유
상수를 다룬다. 모든 socket의 send/publish/request/reply는
Messaging category에 문서화된 operation-builder family를 반환한다 — 이
category는 각 builder가 어디서 시작하고 각 socket type이 고유하게 무엇을
더하는지만 다룬다. socket은 Context의 메서드가 아니라 최상위
createXxxSocket(ctx) 함수(Core category)로 생성된다. 정확한 signature는
contracts/sockets/가
소유한다.
Socket / ConnectableSocket 공유 기반¶
모든 socket type이 확장하는 기반 interface: binding, TLS, monitoring,
disposal, (그리고 StreamSocket을 제외한 모든 socket type의) outbound
connection.
socket.bind('tcp://*:5555');
socket.setTlsServer(certPath, keyPath, true);
const monitor = socket.monitorOpen([MonitorEventType.Connected]);
socket.close();
Options. 아래 모든 구체 socket type은 StreamSocket을 제외하고
ConnectableSocket을 확장한다 — StreamSocket은 Socket을 직접
확장하고 자신의 disconnectRid를 독립적으로 선언한다(아래 참고).
BaseSocket union 타입(PairSocket | PubSocket | SubSocket |
DealerSocket | RouterSocket | XPubSocket | XSubSocket | StreamSocket)은
proxy(Core category)처럼 임의 구체 socket type을
받는 API를 위해 export된다.
| Member | 의미 |
|---|---|
bind(endpoint: string) / unbind(endpoint: string) |
주소에서 listen을 시작/중단 |
close() |
native socket을 닫는다 |
monitorOpen(events?: readonly MonitorEventType[], monitorHwmBytes?: bigint) |
선택 event 집합과 byte HWM으로 caller-owned pull monitor를 연다 |
setTlsServer(cert, key, requireClientCert?) |
bind 전에 적용 |
setTlsClient(ca, hostname, trustSystem?) |
connect 전에 적용 |
ConnectableSocket.connect(endpoint: string) / disconnect(endpoint: string) |
peer 주소로 connect/disconnect |
ConnectableSocket.disconnectRid(routingId: RoutingId) |
해당 routing id로 식별되는 peer를 disconnect |
Completion result. monitorOpen을 제외한 모든 member는 반환값 없이
동기다. monitorOpen은 MonitorSocket(Eventing category)을 동기로
반환한다 — caller가 소유하며 반드시 close해야 한다.
선택 기준. bind/connect 전에 각각 setTlsServer/setTlsClient를
호출한다. 반환된 monitor를 유지하고 recv로 drain한다. callback 등록
경로는 설치하지 않는다.
CommonSocketOptions와 타입별 확장¶
socket.options로 도달하는, 모든 socket type이 공유하는 typed option
facade. getter/setter 메서드 쌍이 아니라 일반 property 접근으로
get/set하는 mutable property의 순수 interface다.
socket.options.sendHwm = 100_000n;
socket.options.linger = 1000;
socket.options.submitRetryMode = SubmitRetryMode.LocalFailure;
Options — CommonSocketOptions.
| Member | 타입 | 의미 |
|---|---|---|
linger |
number, ms |
close()가 대기 중인 send를 flush하기 위해 기다리는 상한 |
sendHwm / recvHwm |
bigint, accounted-byte HWM |
outbound/inbound HWM; 0n은 무제한 |
sendTimeout / recvTimeout / connectTimeout |
number, ms |
blocking send/receive/connect handshake가 기다리는 상한 |
immediate |
boolean |
send가 지금 당장 살아있는 연결을 요구하는지, 아니면 연결이 생길 때까지 큐잉하는지 |
ridDuplicatePolicy |
RidDuplicatePolicyValue |
peer가 기존 routing id를 재사용할 때 벌어지는 일 |
ipv6 |
boolean |
socket이 IPv6 연결을 받아들이는지 |
tcpNoDelay |
boolean |
true면 Nagle 알고리즘을 비활성화 |
tcpKeepalive |
number, -1/0/1 |
OS TCP keepalive 모드 |
maxMsgSize |
bigint |
수신 허용하는 메시지 한 건의 최대 바이트 크기; -1n은 제한 없음 |
lastEndpoint |
string, 읽기 전용 |
실제로 해석된 bind 주소 |
backlog |
number |
listening socket의 대기 연결 큐 길이 |
reconnectInterval / reconnectIntervalMax |
number, ms |
재연결 시도 사이 간격 / 그 간격의 상한 |
submitRetryMode |
순수 number로 타입 지정, SubmitRetryModeValue가 아님 — ridDuplicatePolicy의 typed property와 비교하면 비일관적 |
local back-pressure에서 실패한 submit이 자동 재시도되는지 |
submitRetryTimeout |
number, ms |
submitRetryMode가 요청할 때의 재시도 timeout |
submitRetryAttempts |
number |
submitRetryMode가 요청할 때의 재시도 횟수 상한 |
Options — 타입별 확장.
| 타입 | Member | 의미 |
|---|---|---|
DealerSocketOptions |
probe(boolean) |
connect 시 빈 probe 전송 |
requestTimeout(number, ms) |
request timeout | |
peerWeight(number, 0-100) |
load-balancing 가중치 | |
RouterSocketOptions |
mandatory(boolean) |
알 수 없는 route에서 조용히 버리는 대신 오류 |
handover(boolean) |
ridDuplicatePolicy의 편의 wrapper |
|
probe(boolean) |
connect 시 빈 probe 전송 | |
connectRoutingId(RoutingId \| null, 읽기 전용) / setConnectRoutingId(routingId) |
getter·setter 이름이 비대칭 | |
requestTimeout / peerWeight |
Dealer와 같은 형태, 양방향 모두 | |
StreamSocketOptions |
notify(boolean) |
활성화 시 peer connect/disconnect를 application 메시지로 전달 |
PubSocketOptions |
verbose / verboser(boolean) |
중복 포함 모든 (un)subscribe 메시지를 전달 |
noDrop(boolean) |
back-pressure에서 조용히 버리는 대신 오류 | |
manual / manualLastValue(boolean) |
구독이 approveSubscribe/rejectSubscribe를 요구; manualLastValue는 새로 승인된 구독자에게 topic별 마지막 캐시 메시지도 재전송 |
|
topicsCount(number, 읽기 전용) |
활성 구독 개수 | |
welcomeMessage() / setWelcomeMessage(message: MessageLike) |
새로 연결된 구독자 각각에게 자동 전송; getter는 caller가 소유하는 Message를 반환 |
|
approveSubscribe(routingId) / rejectSubscribe(routingId) |
manual 필요; set-only, getter 없음 |
|
SubSocketOptions |
topicsCount(읽기 전용) |
이 socket이 가진 유일한 타입별 option |
Completion result. 모든 property 읽기/쓰기는 동기다.
선택 기준. 기본값이 배포 환경에 맞지 않을 때 socket이 메시지 교환을
시작하기 전에 sendHwm/recvHwm, linger를 설정한다. wildcard 주소로
bind한 후 lastEndpoint를 읽는다.
PairSocket¶
라우팅이 없는 배타적 1:1 peering socket. DealerSocket이 확장하는
기반 형태 역할을 한다(아래 참고) — Pair와 Dealer에 별도 공유
IMessageSocket 스타일 기반을 주는 dotnet/java/cpp와 달리, 여기선
DealerSocket extends PairSocket이 직접 확장한다.
const pair = createPairSocket(ctx);
pair.send().message(Message.from('ping')).submit_sync();
const received = new Received();
if (pair.recv(received)) { /* ... */ }
Options.
| Member | 의미 |
|---|---|
options |
CommonSocketOptions |
send() |
공유 SendOperation builder를 시작 |
recv(result: Received, flags?: RecvFlags) |
result를 다음 메시지로 채움 |
Completion result. recv는 boolean을 반환한다 —
RecvFlags.DontWait가 설정되고 메시지가 없을 때만 false다.
선택 기준. 배타적 point-to-point 링크엔 PAIR를 쓴다 — peer 라우팅이 없고 load-balance하지 않는다.
DealerSocket¶
연결된 peer 전체에 send를 load-balance하고 routed request를 낼 수
있다. PairSocket을 직접 확장한다(별도 공유 message-socket interface가
아니라).
const dealer = createDealerSocket(ctx);
dealer.setRoutingId(RoutingId.from('worker-3'));
const reply = await dealer.request().message(Message.from('payload')).submit();
Options. PairSocket의 모든 것에 더해:
| Member | 의미 |
|---|---|
options |
DealerSocketOptions로 override됨 |
setRoutingId(routingId) / getRoutingId() |
이 socket 자신의 routing id를 지정/조회, peer가 connect 시 관찰 |
request() |
공유 RequestOperation builder를 시작; target 인자 없음 — DEALER는 API 레벨 peer routing id가 없기 때문 |
Completion result. (상속된) recv는 PairSocket과 같은 boolean
관례를 따른다.
선택 기준. peer가 첫 메시지부터 이를 관찰하도록 connect 전에
setRoutingId를 설정한다. DEALER는 임의 token에 reply할 protocol
envelope helper가 없다 — 대신 수신된 request context
(Received.reply())나 명시적 ROUTER reply 표면에서 답한다.
RouterSocket¶
routing id로 지정된 peer에게 메시지를 보내고, 특정 peer의 request에
reply할 수 있다. PairSocket이 아니라 ConnectableSocket을 직접
확장한다.
const router = createRouterSocket(ctx);
await router.send(peerRid).message(Message.from('hello')).submit();
Options.
| Member | 의미 |
|---|---|
options |
RouterSocketOptions |
send(routingId) |
공유 SendOperation을 그 peer로 향해 시작 |
recv(result: Received, flags?: RecvFlags) |
result를 다음 메시지로 채움 |
setRoutingId(routingId) / getRoutingId() |
이 socket 자신의 routing id를 지정/조회, peer가 connect 시 관찰 |
request(peerRid) |
Messaging category의 RequestOperation, 특정 peer로 향함 |
reply(peerRid, token: ReplyToken) |
Messaging category의 ReplyOperation, 이 ROUTER가 받은 opaque capability를 소비 |
Completion result. Managed send와 request completion은 해당 Promise
또는 blocking terminal로만 전달된다. recv는 위 boolean 관례를 따른다.
선택 기준. DEALER가 특정 peer를 지정할 수 없는 ROUTER 주도·ROUTER
응답 request/reply엔 request(peerRid)/reply(peerRid, token)을 쓴다.
ReplyToken은 opaque하고 socket-owned이며 one-shot인 채로 유지한다.
PubSocket / XPubSocket¶
PUB는 매칭되는 구독자가 없으면 버리는 topic-filtered 메시지를
publish하고, XPUB는 추가로 구독자의 subscribe/unsubscribe event를
노출한다. XPubSocket extends PubSocket.
const pub = createPubSocket(ctx);
pub.publish('prices').message(Message.from(tick)).submit();
const xpub = createXPubSocket(ctx);
const evt = new SubscriptionEvent();
if (xpub.receiveSubscriptionEvent(evt)) { /* ... */ }
Options. PubSocket extends ConnectableSocket; XPubSocket extends PubSocket.
| Member | 의미 |
|---|---|
options |
PubSocketOptions |
publish(topic: string) |
공유 SendOperation builder를 시작 |
receiveSubscriptionEvent(result: SubscriptionEvent, flags?: RecvFlags) |
XPubSocket에만 있음; result를 다음 subscribe/unsubscribe로 채움 |
PubSocket엔 setRoutingId/getRoutingId가 없다(둘 다 있는 dotnet의
IPubSocket과 다름).
Completion result. receiveSubscriptionEvent는 위와 같은 관례로
boolean을 반환한다.
선택 기준. receiveSubscriptionEvent로 구독자 변동을 관찰하거나
PubSocketOptions.manual/approveSubscribe/rejectSubscribe로 수동
admission을 하려면 특별히 XPubSocket을 쓴다. 그 외엔 publish 자체는
둘이 같게 동작한다.
SubSocket / XSubSocket¶
SUB는 구독을 socket option으로 설정하는 방식으로 topic을 구독하고,
XSUB는 대신 구독을 메시지로 실어 나른다. XSubSocket extends SubSocket
{} — 완전히 빈 interface 본문으로, 지금까지 다룬 모든 wrapper binding
중 가장 순수한 delta-only 선언이다.
const sub = createSubSocket(ctx);
sub.setSubscription('prices.');
const msg = new TopicMessage();
if (sub.subscribe(msg)) { /* ... */ }
Options. SubSocket extends ConnectableSocket.
| Member | 의미 |
|---|---|
options |
SubSocketOptions |
setSubscription(filter: string) / unsetSubscription(filter: string) |
topic filter를 추가/제거; 구독은 누적된다 |
subscriptionAt(index: number) |
SubscriptionEntry \| null — 해당 index의 filter |
subscribe(result: TopicMessage, flags?: RecvFlags) |
result를 다음 매칭 publish로 채움 |
XSubSocket은 아무것도 더하지 않는다 — 모든 member가 상속된 SubSocket
표면 그대로다.
Completion result. subscribe는 위와 같은 관례로 boolean을
반환한다.
선택 기준. 일반적인 경우엔 SubSocket을 쓴다. 구독을 일반 메시지로
실어 날라야 할 때만 특별히 XSubSocket을 쓴다 — interface 자체는 둘을
구분할 게 없으므로 선택은 전적으로 어떤 구체 타입을 생성하는지
(createSubSocket vs createXSubSocket)에 달려 있다.
StreamSocket¶
다른 모든 socket type이 쓰는 zlink wire protocol 밖에서, raw TCP peer와
framed packet을 직접 주고받는다. (ConnectableSocket이 아니라)
Socket을 확장하고 자신의 disconnectRid를 독립적으로 선언한다.
const stream = createStreamSocket(ctx);
stream.options.recvMode = StreamRecvMode.Packet;
const packet = new StreamPacket();
if (stream.recvPacket(packet)) { /* packet.routingId/header/body 사용 */ }
packet.close();
Options.
| Member | 의미 |
|---|---|
options |
StreamSocketOptions |
send(routingId) |
공유 SendOperation을 그 peer로 향해 시작 |
recv(result: Received, flags?: RecvFlags) |
다음 RAW-mode record를 pull |
recvPacket(result: StreamPacket, flags?: RecvFlags) |
다음 PACKET-mode header/body를 재사용 storage로 pull |
setRoutingId(routingId) / getRoutingId() |
이 socket 자신의 routing id를 지정/조회, peer가 connect 시 관찰 |
disconnectRid(routingId) |
StreamSocket이 ConnectableSocket의 사본을 상속하지 않으므로 이 interface에 직접 선언됨 |
Completion result. recv와 recvPacket은 위 boolean 관례를 따른다.
Caller가 packet의 header/body를 소유하며 packet.close()로 해제한다.
선택 기준. 첫 successful bind/connect 전에 options.recvMode를
StreamRecvMode.Raw 또는 .Packet으로 정한다. 이후 변경은 invalid state며,
선택한 pull API를 drain한다.
Socket 상수¶
위 모든 항목에서 참조하는 공유 상수 객체와 그 파생 타입.
| 상수 | 사용처 | 값 |
|---|---|---|
SocketType |
내부 socket 종류 식별 | 이중 케이싱: ANY/PAIR/PUB/SUB/DEALER/ROUTER/XPUB/XSUB/STREAM과 Any/Pair/Pub/Sub/Dealer/Router/XPub/XSub/Stream 둘 다 동일한 숫자값의 alias로 export됨 |
SOCKET_MONITOR_EVENT_ALL |
호환성 상수 | 0x7FFFF; 현행 monitorOpen은 숫자 mask 대신 readonly MonitorEventType[]를 받음 |
RidDuplicatePolicy |
CommonSocketOptions.ridDuplicatePolicy, RouterSocketOptions.handover |
Reject, Handover |
SubmitRetryMode |
CommonSocketOptions.submitRetryMode(property 자체는 순수 number로 타입 지정) |
Off, LocalFailure |
SendFlags |
export된 호환성 상수; managed send/request/reply terminal은 받지 않음 | None, DontWait |
RecvFlags |
모든 recv/subscribe/receiveSubscriptionEvent |
None, DontWait |
PollEventFlag |
Poller 등록/wait(Eventing category) | PollIn, PollOut, PollErr, PollPri, PollCompletion |
선택 기준. RecvFlags.DontWait는 pull API가 block하는 대신 false를
반환해야 할 때 쓴다. Managed send/request/reply terminal은 의도적으로
DontWait를 노출하지 않는다. monitorOpen 필터에는 MonitorEventType
값 목록을 넘긴다.
contracts/sockets/와
Node 바인딩 스펙에서 전체 근거를 확인한다.