install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/72-network-ws-client" ~/.claude/skills/majiayu000-claude-skill-registry-72-network-ws-client && rm -rf "$T"
manifest:
skills/data/72-network-ws-client/SKILL.mdsource content
72-network-ws-client
Status: ACTIVE
AppliesTo: v10
Type: Policy / Requirements
Purpose
Devian 런타임에 WebSocket 기반 클라이언트 런타임을 추가한다.
이 SKILL은 정책/요구사항/설계 의도를 정의한다. 구현 및 공개 API는 코드가 정답이며, 여기의 시그니처/예시는 참고용이다.
Namespace 정책: 모든 타입은
단일을 사용한다. 네트워크 계열 public API는namespace Devian접두사로 명확화한다.Net
Scope
목표 (In Scope)
: WebSocket 클라이언트 (sync public API)NetWsClient- Non-WebGL: background threads 기반
- WebGL: thread 없음,
기반 폴링Tick()
: 프레임 수신 → 디스패치 라우팅NetClient
: opcode 기반 디스패치 인터페이스 (이미 Net 포함, 유지)INetRuntime
: 프레임 포맷 파서 (NetFrameV1
)[opcode:int32LE][payload...]
비목표 (Out of Scope)
- TypeScript 변경 없음
- HTTP/RPC는 별도 SKILL에서 다룸
- 기존
,INetPacketSender
API 변경 없음NetPacketEnvelope
Relationship with Devian
이 SKILL은
namespace Devian에 네트워크 기능을 제공한다.
| 기존 | 추가 (이 SKILL) |
|---|---|
| 변경 없음 |
| 변경 없음 |
| - | |
| - | |
| - | |
| - | |
File Paths (Reference)
framework-cs/module/Devian/src/Net/ ├── NetFrameV1.cs ├── INetRuntime.cs ├── NetClient.cs └── Transports/ └── NetWsClient.cs
API Signatures (Reference)
Note: 아래는 이해를 돕기 위한 참고 예시이며, 최종 시그니처/공개 API는 코드가 정답이다.
코드 변경 시 이 문서를 'SSOT'로 맞추지 않는다. 필요하면 문서를 참고 수준으로 갱신한다.
NetFrameV1
namespace Devian { public static class NetFrameV1 { /// <summary> /// Frame format: [opcode:int32LE][payload...] /// </summary> public static bool TryParse( ReadOnlySpan<byte> frame, out int opcode, out ReadOnlySpan<byte> payload); /// <summary> /// Build frame into destination buffer. /// Returns bytes written. /// </summary> public static int Build( Span<byte> destination, int opcode, ReadOnlySpan<byte> payload); /// <summary> /// Calculate total frame size. /// </summary> public static int CalculateSize(int payloadLength); } }
INetRuntime
namespace Devian { public interface INetRuntime { /// <summary> /// Dispatch inbound message by opcode. /// Returns true if handled, false otherwise. /// </summary> bool TryDispatchInbound(int sessionId, int opcode, ReadOnlySpan<byte> payload); } }
NetClient
namespace Devian { public sealed class NetClient { public NetClient(INetRuntime runtime); /// <summary> /// Called by transport when a complete frame is received. /// Parses frame and dispatches to runtime. /// </summary> public void OnFrame(int sessionId, ReadOnlySpan<byte> frame); } }
NetWsClient
namespace Devian { public sealed class NetWsClient : IDisposable { public NetWsClient(NetClient core, int sessionId = 0); public bool IsOpen { get; } public event Action? OnOpen; public event Action<ushort, string>? OnClose; public event Action<Exception>? OnError; /// <summary> /// Synchronously connect and start background recv/send threads. /// </summary> public void Connect(string url, string[]? subProtocols = null); /// <summary> /// Synchronously enqueue frame for sending. /// </summary> public void SendFrame(ReadOnlySpan<byte> frame); /// <summary> /// Request graceful close. /// </summary> public void Close(); /// <summary> /// Process dispatch queue on calling thread (Unity main thread). /// WebGL에서는 WS_PollEvent drain도 수행한다. /// /// 문서 표준 호출명: Tick() /// Update()는 alias로 유지 (레거시, Unity MonoBehaviour.Update 혼동 방지) /// </summary> public void Tick(); /// <summary> /// Alias for Tick(). 레거시 호환용, 사용 비권장. /// Unity MonoBehaviour.Update()와 혼동 금지. /// </summary> [Obsolete("Use Tick() instead")] public void Update(); public void Dispose(); } }
Frame Format (NetFrameV1)
+------------------+------------------+ | opcode (4 bytes) | payload (N bytes)| | int32 LE | raw bytes | +------------------+------------------+
- opcode: 32-bit signed integer, little-endian
- payload: 0 or more bytes
Close → OnClose 보장 (Hard Rule)
로컬 Close() 호출 시 OnClose 이벤트가 반드시 발생해야 한다.
- 서버 응답 여부와 무관하게 OnClose 발생 필수
- RecvLoop blocking 중이어도 OnClose 발생 필수
- CancellationToken.None으로 무한 대기 금지
위반 시 FAIL:
- Close() 후 OnClose 안 오면 FAIL
- 서버가 응답 안 해도 일정 시간 내 OnClose 와야 함
Performance / GC Rules (Hard Rules)
MUST
- ToArray() 금지: 수신/송신 경로에서
호출 금지ToArray() - ArrayPool 기반 버퍼 재사용:
- 수신:
→ 누적 → 처리 후 재사용ArrayPool<byte>.Shared.Rent() - 송신: caller span을 rented buffer에 복사 → 전송 후
Return()
- 수신:
- Send는 sync enqueue (Non-WebGL):
은 즉시 반환, 실제 전송은 send threadSendFrame() - Receive는 pool buffer 누적 (Non-WebGL):
에서만 core로 전달EndOfMessage
WebGL Note: 이 문서에서 "send/recv thread"는 Non-WebGL을 의미한다. WebGL에서는 스레드가 없으며, 수신은 콜백 전달이 아니라 폴링 전달로 수행된다. ToArray 금지, ArrayPool 재사용, 핫 경로 alloc 금지는 동일하게 적용된다. ptr/len free 규칙은 77-webgl-jslib-memory-rules에 위임한다.
MUST NOT
- public API에
노출 금지 (async
,Connect
,SendFrame
는 sync)Close - 핫 경로에서 allocation 금지
Threading Model
┌─────────────────┐ │ Main Thread │ │ (Unity Update) │ │ │ │ Tick() ────────┼──→ dispatch queue drain + (WebGL: WS_PollEvent drain) │ SendFrame() ───┼──→ send queue enqueue │ Connect() │ │ Close() │ └─────────────────┘ │ ▼ (Non-WebGL only) ┌─────────────────┐ ┌─────────────────┐ │ Send Thread │ │ Recv Thread │ │ │ │ │ │ dequeue ───────┼──→ │ ReceiveAsync │ │ SendAsync │ │ ──→ OnFrame() │ └─────────────────┘ └─────────────────┘
Tick() vs Update() 표준화:
= dispatch queue drain + (WebGL이면 WS_PollEvent drain)Tick() =Update()alias (레거시, Unity MonoBehaviour.Update 혼동 방지 목적상 사용 비권장)Tick()
WebGL Exception (UNITY_WEBGL && !UNITY_EDITOR
)
UNITY_WEBGL && !UNITY_EDITORWebGL에서는 브라우저 제약으로 스레드 기반 send/recv 루프를 사용하지 않는다.
폴링 기반 모델 (콜백/SendMessage 금지):
가 이벤트 큐를 유지.jslib
에서Tick()
를 최대 N개까지 drain하여:WS_PollEvent
→ 내부 dispatch queue에 enqueueOPEN/CLOSE/ERROR
→MESSAGE(ptr, len)
→Marshal.Copycore.OnFrame(sessionId, frame)
- 송신:
+ArrayPool<byte>
→GCHandle.Alloc(Pinned)
(ToArray 없음)WS_SendBinary(ptr,len) - 수신:
가.jslib
으로 WASM heap에 복사 → C#이_malloc
로Marshal.Copy
에 복사 후 처리 →ArrayPool<byte>
로 해제WS_FreeBuffer(ptr)
메모리 규칙:
- ptr/len/문자열 Free 규칙은 77-webgl-jslib-memory-rules 참조
계약 정본:
Event Dispatch
| Event | Parameters | 설명 |
|---|---|---|
| - | 연결 성공 |
| | 연결 종료 |
| | 오류 발생 |
- 이벤트는 dispatch queue를 통해
에서 실행 (Unity 호환)Tick()
는Update()
alias (레거시 호환)Tick()- Unity가 아닌 환경에서는 즉시 호출로 변경 가능
Build Target
유지netstandard2.1
이 누락되면ClientWebSocket
패키지 조건부 추가 가능System.Net.WebSockets.Client- 기본은 패키지 추가 없이 시도
Reference
- Parent Module:
(단일 런타임 모듈,Devian
)namespace Devian - Related:
skills/devian-core/10-core-runtime/SKILL.md - WebGL 폴링 계약: 76-webgl-ws-polling-bridge
- WebGL 메모리 규칙: 77-webgl-jslib-memory-rules