콘텐츠로 이동

한국어 | English

레퍼런스 목차

02. Messaging

이 category는 message 소유권, receive envelope 타입(Received, TopicMessage, SubscriptionEvent), 그리고 Sockets category의 모든 socket-type 진입점이 반환하는 send/request/reply operation-builder 공유 형태를 다룬다. 정확한 signature는 Contracts/Messaging/이 소유한다. Contracts/Messaging/MessageEnvelopeParts.csinternal이라 public contract 항목이 없다.


Message

zlink message payload 하나를 소유한다 — 모든 send·request·reply·receive API가 옮기는 단위다.

using Message empty = new Message();
using Message sized = new Message(4096);
using Message copy = Message.From("payload"u8);
using Message fromString = Message.From("hello", Encoding.UTF8);

옵션.

Member 매개변수 의미
Message() 빈 메시지
Message(int size) 음수는 ArgumentOutOfRangeException 쓰기 가능 storage
Message(ReadOnlySpan<byte>) / Message(ReadOnlyMemory<byte>) 스냅샷 복사
From(byte[]) / From(ReadOnlySpan<byte>) / From(ReadOnlyMemory<byte>) / From(ReadOnlySequence<byte>) static factory, 스냅샷 복사
From(Message) 다른 메시지의 payload 복사
From(string) / From(string, Encoding) 기본 UTF-8 인코딩
Size / IsEmpty / RefCount 진단
AsSpan() / AsReadOnlySpan() 이 인스턴스 storage에 backing된 쓰기/읽기 전용 view
AsReadOnlyMemory() native-backed message는 여기서 managed memory로 복사
ToArray() / GetString() / GetString(Encoding) 독립된 managed 복사본
CopyTo(Span<byte>) / CopyTo(IBufferWriter<byte>) / TryCopyTo(Span<byte>, out int) caller buffer로 복사

완료 결과. 모두 동기다. MessageIDisposable/IAsyncDisposable이다 — 해제하면 payload storage가 반환된다. 이 메시지를 소비하는 submit(아래 Sockets/Messaging builder 형태)은 성공 후 managed instance를 빈 상태로 남긴다 — 그 후 payload를 읽으면 예외가 발생하지만, disposing은 여전히 안전하고 여전히 필요하다.

선택 기준. outbound payload를 만들 땐 크기 지정 또는 스냅샷 복사 생성자/factory를 쓴다. 추가 복사 없이 그대로 읽거나 쓸 땐 AsSpan()/AsReadOnlySpan()을, 독립된 managed 복사가 허용될 땐 ToArray()/GetString()을 쓴다.


Received.Create()

caller-provided-storage receive 형태를 위한 재사용 가능한 receive envelope을 만든다.

using Received received = Received.Create();
bool ok = dealer.Recv(received);

옵션. 인자 없음 — Received는 public 생성자가 없다, Create()만 있다.

완료 결과. Received를 동기로 반환한다. caller가 소유하며 반드시 dispose해야 한다. receive API(Sockets category)는 성공적인 호출마다 내부 상태를 덮어쓴다.

선택 기준. receive loop·스레드마다 Received 하나를 만들어 호출마다 새로 할당하는 대신 재사용한다.


Received member

envelope 메타데이터·message part를 읽거나, envelope의 source를 향한 reply/send를 시작한다.

if (received.ReplyToken is { } token)
{
    received.Reply().Message(Message.From("ok")).Submit();
}
Message first = received.FirstPart();

옵션.

Member 반환 의미
RoutingId RoutingId? receive 경로가 제공할 때만 존재
ReplyToken ReplyToken? ROUTER request에 있는 opaque reply capability
MessageType ReceivedMessageType Raw/Request/Reply/ErrorReply
Parts IReadOnlyList<Message> 이 envelope이 담은 모든 message part
IsSinglePart bool Parts가 정확히 하나인지
FirstPart() Message 첫 part, 소유권 이전 없음
SinglePartOrThrow() Message 단일 part, Parts가 둘 이상이면 예외
Reply() builder ReplyToken이 값을 가질 때만 유효 — 아래 공유 builder 형태 참고
Send() builder envelope의 source route로 향함

완료 결과. 모두 동기다. Dispose()는 다른 API가 이미 소유권을 이전하지 않은 한 이 envelope이 소유한 message part를 해제한다. Reply()/Send()는 아래 공유 operation-builder 형태의 builder를 반환한다.

선택 기준. MessageType/ReplyToken으로 분기해 envelope이 reply 가능한지 판단한다. source route를 따로 찾지 않고 요청에 답하려면 Reply()를 쓴다.


TopicMessage

수신된 publish 하나 — topic, source routing id, message part를 담는다.

using TopicMessage published = new TopicMessage();
bool ok = sub.Recv(published);
string topic = published.Topic;

옵션.

Member 반환 의미
TopicMessage() public 생성자(Received와 달리 factory가 아니라 직접 생성)
ReleaseForReuse() void 현재 part와 metadata를 해제하고 내부 topic 수신 버퍼는 유지해 다음 Subscribe에서 재사용; terminal Dispose() 뒤에는 ObjectDisposedException
RoutingId RoutingId? 발행자의 routing id, receive 경로가 제공할 때만 존재
Topic string topic byte에서 지연 디코딩
Parts IReadOnlyList<Message> 이 publish가 담은 모든 message part
IsSinglePart bool Parts가 정확히 하나인지
FirstPart() / SinglePartOrThrow() Message Received와 같은 형태 — 소유권 이전 없는 첫 part, 또는 단일 part(multipart면 예외)

완료 결과. 동기다. Dispose()는 이 instance가 소유한 part와 topic 버퍼를 해제한다. ReleaseForReuse()는 현재 part와 metadata를 해제하지만 내부 topic 수신 버퍼는 유지하므로 호출자는 같은 storage를 다음 Subscribe에서 재사용할 수 있다. 해제한 이전 part는 더 이상 사용하지 않는다. 열린 instance에서는 ReleaseForReuse()를 반복 호출할 수 있다. terminal Dispose() 뒤에는 ObjectDisposedException을 던지며 instance를 다시 열지 않는다.

선택 기준. Received를 재사용하는 것과 같은 방식으로 subscribe-receive loop 전체에서 instance 하나를 재사용한다.


SubscriptionEvent

XPUB socket이 관찰한 구독자 한 명의 subscribe·unsubscribe를 보고한다.

using SubscriptionEvent evt = new SubscriptionEvent();
bool ok = xpub.Recv(evt);

옵션.

Member 반환 의미
SubscriptionEvent() public 생성자
RoutingId RoutingId? 구독자의 routing id, receive 경로가 제공할 때만 존재
Topic string 구독·구독 취소된 topic
Subscribed bool 구독이면 true, 구독 취소면 false
SubscriptionEntry(string Filter, bool IsPattern) record 활성 구독 하나

완료 결과. 동기다. dispose 없음 — 이 타입은 자신의 native resource를 소유하지 않는다.

선택 기준. application 레벨 프로토콜 메시지로 구독자 변동을 추론하는 대신, XPUB socket의 subscription-event receive 경로(Sockets category)에서 이를 관찰한다.


Send / request / reply operation-builder 형태

Sockets category의 모든 Send, routed send, Publish, Request, Reply 진입점이 반환하는, part·flag·terminal submit을 누적하는 fluent builder.

dealer.Send(routingId).Message(Message.From("part-1")).Message(Message.From("part-2")).Submit();

IReadOnlyList<Message> reply = await dealer
    .Request(routingId)
    .Message(Message.From("payload"))
    .Timeout(TimeSpan.FromSeconds(5))
    .Async();

received.Reply().Message(Message.From("ok")).Submit();

옵션.

단계 Member 의미
SendOperation .Message(Message) chain 시작
SendSubmitOperation .Message(...) / .Submit() / .Async(CancellationToken) part 추가 뒤 blocking 또는 Task terminal 선택
RequestOperation/RequestSubmitOperation Send와 동일 + .Timeout(TimeSpan) send chain을 그대로 반영하며 reply 대기 timeout을 더함
RequestSubmitOperation terminal .Submit() / .Async(CancellationToken) blocking reply 또는 completion-backed Task reply 결과
ReplyOperation/ReplySubmitOperation Send와 같은 형태, flags 단계 없음 core reply 함수가 send-flag 인자를 받지 않음
Messages(IReadOnlyList<Message>) MessageOperations extension 네 family 전체의 모든 단계에서 여러 part를 순서대로 한 번에 추가; 독립 진입점 아님

완료 결과. 모두 동기 호출이다; part는 성공적인 submit에서만 소비되며, 실패 시 소유권은 caller에게 복원된다.

Terminal 반환 의미
SendSubmitOperation.Submit() void Core local admission까지 blocking, 실패하면 ZlinkException
SendSubmitOperation.Async(CancellationToken) Task DONTWAIT submit을 socket completion queue에서 settle
ReplySubmitOperation.Submit() void 실패하면 ZlinkException을 던짐
RequestSubmitOperation.Async(CancellationToken) Task<IReadOnlyList<Message>> caller가 reply message를 소유하며 반드시 dispose해야 함
RequestSubmitOperation.Submit() IReadOnlyList<Message> completion queue가 reply를 낼 때까지 blocking, caller가 part dispose

선택 기준. async 코드에서는 .Async()를, blocking 가능한 thread에서는 .Submit()을 쓴다. 목적지 route를 손으로 재구성하는 대신 Received envelope의 Reply()/Send()를 쓴다.


Contracts/Messaging/.NET 바인딩 스펙에서 전체 근거를 확인한다.