가이드 · 개발자 SDK

.NET에서 NAT 통과 P2P 연결 구현하기

서로 다른 네트워크에 있는 두 기기를 직접 연결하려면 NAT 통과(hole-punching), 막힐 때의 릴레이 폴백, 그리고 종단간 암호화가 함께 필요합니다. 이 가이드는 .NET(C#) 애플리케이션에서 P2P 연결을 처음부터 구현할 때 실제로 부딪히는 문제들을 정리하고, 이를 클라이언트 SDK로 바로 쓰는 방법(ConnectKit)을 함께 소개합니다.

NAT 통과가 어려운 이유

가정·사무실 네트워크의 PC는 대부분 공인 IP가 아니라 NAT(공유기) 뒤의 사설 IP를 씁니다. 두 PC가 직접 통신하려면 서로의 공인 주소·포트를 알아내야 하는데, NAT 장비의 포트 매핑 방식이 풀콘(Full Cone)·제한콘(Restricted Cone)·포트제한콘(Port-Restricted Cone)·대칭(Symmetric) NAT로 제각각이라 하나의 절차로 모두 처리할 수 없습니다. STUN류 기법으로 매핑을 알아내고, 양쪽이 동시에 패킷을 보내 매핑을 "뚫는" 홀펀칭을 시도하되, 양쪽 모두 대칭 NAT인 조합처럼 직결이 근본적으로 불가능한 경우까지 대비해야 합니다.

직접 구현할 때 필요한 것들

이 목록 하나하나는 널리 알려진 기법이지만, 전부를 프로덕션 품질로 조합해 유지보수하는 작업은 결코 작지 않습니다. 그래서 이 계층을 라이브러리로 가져다 쓰는 선택지가 널리 쓰입니다.

ConnectKit으로 건너뛰기

ConnectKit은 위 목록의 연결 계층을 클라이언트 SDK로 제공합니다. NAT 홀펀칭이 가능한 경로는 P2P로 직결하고, 불가능하면 릴레이로 자동 폴백하며, AES-256-GCM 기반 종단간 암호화와 안전한 키 교환(J-PAKE)을 함께 처리합니다. 앱 코드에서는 연결·재시도·경로 선택의 복잡함이 감춰지고, 간단한 API로 스트림을 주고받습니다. ConnectKit은 ServerKit 코디네이터·릴레이·게이트웨이와 동일한 와이어 프로토콜을 쓰므로 곧바로 연동됩니다.

연결 위에 무엇을 얹을까 — 세션과 디바이스

연결(ConnectKit) 자체는 바이트 스트림을 안전하게 여는 역할만 합니다. 그 위에 무엇을 올릴지는 용도에 따라 달라집니다. 화면 캡처·원격 제어·클립보드·파일·오디오가 필요하면 SessionKit을, RPC·Pub/Sub·텔레메트리·원격 실행·펌웨어 배포처럼 구조화된 디바이스 제어가 필요하면 DeviceKit을 같은 연결 위에 얹습니다. 두 SDK 모두 전송 방식을 가리지 않으므로 ConnectKit이 아닌 WebSocket·TCP·SSH 터널 위에서도 동작합니다.

어떤 구성이 필요한지 정리

필요한 것담당 SDK비용
NAT 통과 + 종단간 암호화 연결ConnectKit영구 무료
연결을 중개하는 서버(코디네이터·릴레이·게이트웨이)ServerKit(자체호스팅)5피어까지 무료, 이후 규모별 유료
화면·입력·클립보드·파일·오디오SessionKitStandard 무료, Premium 개발자 시트별 유료
RPC·텔레메트리·원격 실행·펌웨어DeviceKitPremium·Suite 플랜 포함

정확한 구성별 가격은 가격 안내에서 확인할 수 있고, SDK 바이너리는 다운로드 페이지에서 받습니다.

직접 구현 vs SDK — 실제로 줄어드는 작업

NAT 통과를 직접 구현하는 프로젝트에서 시간이 가장 많이 드는 부분은 처음 연결에 성공하는 것이 아니라, 다양한 네트워크 환경(모바일 핫스팟, 기업 방화벽, 이중 NAT, CGNAT)에서 꾸준히 재현 가능하게 만드는 과정입니다. STUN 서버 하나만 두면 프로토타입은 금방 동작하지만, 실제 배포 환경에서는 타임아웃 값 조정, 여러 경로 동시 시도, 릴레이 전환 시점 판단처럼 눈에 잘 띄지 않는 엣지 케이스가 대부분의 버그 리포트를 차지합니다. ConnectKit을 쓰면 이렇게 튜닝된 경로 선택 로직을 그대로 재사용하고, 애플리케이션 코드는 세션이 열린 뒤의 로직에만 집중할 수 있습니다.

자주 묻는 질문

NAT 홀펀칭을 처음부터 직접 구현하는 게 왜 어려운가요?
NAT 장비마다 포트 매핑 방식(풀콘·제한콘·대칭 NAT 등)이 달라 상대의 공인 주소·포트를 알아내는 절차(STUN류 기법)를 여러 경우의 수로 처리해야 하고, 그래도 뚫리지 않는 조합(특히 양쪽 모두 대칭 NAT인 경우)을 대비해 릴레이 폴백까지 마련해야 합니다. 재시도·타임아웃·경로 전환 로직까지 더하면 직접 구현 범위가 빠르게 커집니다.

ConnectKit은 소켓을 직접 여나요, 아니면 다른 전송 위에서 동작하나요?
ConnectKit 자체는 NAT 통과·종단간 암호화 파이프를 제공하는 클라이언트 SDK로, 연결을 중개하는 서버 (코디네이터·릴레이·게이트웨이)가 필요합니다. 서버는 ServerKit을 자체호스팅하거나 관리형 서비스를 이용합니다. 반면 세션 계층(SessionKit)은 전송 방식을 가리지 않아, ConnectKit 위든 WebSocket·TCP·SSH 터널 위든 그대로 얹을 수 있습니다.

연결이 P2P로 직결되지 않으면 어떻게 되나요?
홀펀칭 경로가 막히면 릴레이로 자동 폴백해 트래픽을 중계합니다. 세션 암호는 두 기기에서만 생성되므로 (J-PAKE 등 종단간 암호화), 릴레이를 거치더라도 중계 서버는 내용을 볼 수 없습니다.

ConnectKit은 무료인가요?
네. ConnectKit 클라이언트 SDK는 영구 무료입니다. 연결을 중개하는 서버(ServerKit)는 5피어까지 무료이며 이후 피어 규모별 유료 티어가 적용됩니다.

ConnectKit은 클라이언트 SDK이며 연결을 중개하는 서버가 필요합니다. 서버는 ServerKit을 자체호스팅하거나 관리형 서비스를 이용하세요.
Guides · Developer SDKs

Implementing NAT-traversal P2P connections in .NET

Connecting two devices on different networks directly takes NAT traversal (hole-punching), relay fallback for when that's blocked, and end-to-end encryption on top. This guide walks through what actually goes into implementing P2P connectivity in a .NET (C#) application from scratch, and how a client SDK (ConnectKit) skips the work.

Why NAT traversal is hard

Most PCs on a home or office network sit behind NAT with a private IP, not a public one. For two PCs to talk directly, each needs to learn the other's public address and port — but NAT devices map ports differently (Full Cone, Restricted Cone, Port-Restricted Cone, Symmetric NAT), so no single procedure covers every case. You use STUN-style techniques to discover the mapping, attempt hole-punching by having both sides send packets simultaneously, and still have to plan for combinations — like both ends behind Symmetric NAT — where a direct link is fundamentally impossible.

What building it yourself requires

Each item on this list is individually well-known, but combining and maintaining all of it at production quality is no small project — which is why reaching for a library at this layer is a common choice.

Skipping the work with ConnectKit

ConnectKit ships the connection layer above as a client SDK: direct P2P where NAT hole-punching works, automatic relay fallback where it doesn't, and AES-256-GCM end-to-end encryption with a secure key exchange (J-PAKE), all handled for you. Your app code doesn't see the complexity of connect, retry, and path selection — it just exchanges streams over a small API. ConnectKit speaks the same wire protocol as the ServerKit coordinator, relay, and gateway, so it just connects.

What to layer on top — session and device

The connection layer (ConnectKit) only opens a secure byte stream. What you build on top depends on your use case. For screen capture, remote control, clipboard, files, and audio, layer on SessionKit; for structured device control — RPC, pub/sub, telemetry, remote exec, firmware delivery — layer on DeviceKit. Both are transport-agnostic, so they also work over WebSocket, TCP, or an SSH tunnel instead of ConnectKit.

What you need, at a glance

NeedSDKCost
NAT-traversing, end-to-end-encrypted connectionConnectKitFree forever
Broker server (coordinator, relay, gateway)ServerKit (self-hosted)Free up to 5 peers, then paid by scale
Screen, input, clipboard, files, audioSessionKitStandard free, Premium per developer seat
RPC, telemetry, remote exec, firmwareDeviceKitIncluded in Premium · Suite

See exact pricing per configuration on the Pricing page, and get the SDK binaries from the Downloads page.

Build it yourself vs. an SDK — what actually shrinks

In a from-scratch NAT-traversal project, the time sink isn't getting the first connection to succeed — it's making that success reproducible across mobile hotspots, corporate firewalls, double NAT, and CGNAT. A single STUN server gets a prototype working quickly, but in real deployments, most bug reports trace back to less visible edge cases: tuning timeout values, trying multiple paths concurrently, and deciding when to fall back to a relay. With ConnectKit, that tuned path-selection logic is already done, and your application code can focus purely on what happens once the session is open.

Frequently asked questions

Why is implementing NAT hole-punching from scratch hard?
NAT devices map ports differently (Full Cone, Restricted Cone, Symmetric NAT, and more), so discovering the peer's public address and port (STUN-style techniques) has to handle several cases, and you still need a relay fallback for combinations that can never connect directly (especially both ends behind Symmetric NAT). Add retry, timeout, and path-switching logic, and the scope of a from-scratch implementation grows quickly.

Does ConnectKit open sockets directly, or does it run over another transport?
ConnectKit itself is a client SDK that provides the NAT-traversal, end-to-end-encrypted pipe, and it needs a broker server (coordinator, relay, gateway) — self-host ServerKit or use the managed service. The session layer (SessionKit), by contrast, is transport-agnostic and layers just as well over ConnectKit as over WebSocket, TCP, or an SSH tunnel.

What happens if the connection can't go direct P2P?
When the hole-punch path is blocked, it falls back automatically to a relay that forwards traffic. Because the session key is created on the two devices only (end-to-end encryption via J-PAKE), the relay still can't see the content even though it's forwarding it.

Is ConnectKit free?
Yes. The ConnectKit client SDK is free forever. The broker server (ServerKit) is free up to 5 peers, with paid tiers by peer scale beyond that.

ConnectKit is a client SDK and needs a server to broker connections. Self-host ServerKit or use the managed service.