콘텐츠로 이동

한국어 | 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을 확장한다 — StreamSocketSocket을 직접 확장하고 자신의 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는 반환값 없이 동기다. monitorOpenMonitorSocket(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. recvboolean을 반환한다 — 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. (상속된) recvPairSocket과 같은 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로 채움

PubSocketsetRoutingId/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) StreamSocketConnectableSocket의 사본을 상속하지 않으므로 이 interface에 직접 선언됨

Completion result. recvrecvPacket은 위 boolean 관례를 따른다. Caller가 packet의 header/body를 소유하며 packet.close()로 해제한다.

선택 기준. 첫 successful bind/connect 전에 options.recvModeStreamRecvMode.Raw 또는 .Packet으로 정한다. 이후 변경은 invalid state며, 선택한 pull API를 drain한다.


Socket 상수

위 모든 항목에서 참조하는 공유 상수 객체와 그 파생 타입.

상수 사용처
SocketType 내부 socket 종류 식별 이중 케이싱: ANY/PAIR/PUB/SUB/DEALER/ROUTER/XPUB/XSUB/STREAMAny/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 바인딩 스펙에서 전체 근거를 확인한다.