[DevNotes] WebRTC 연결 흐름
서론
오늘은 아무도 알려주지 않는 WebRTC를 사용한 P2P통신이라는 강의를 들으며 공부한 WebRTC의 연결 흐름을 단계별로 정리해보았습니다.
사운드 AI를 개발하는 스타트업에서 근무하면서 실시간으로 오디오 데이터를 다룰 일이 많다보니 자연스럽게 WebSocket이나 WebRTC, gRPC와 같은 실시간 통신 기술에 관심을 갖게 되었습니다.
WebRTC를 실제 웹 서비스에 적용하는 강의를 발견하여 수강하였습니다. 이 강의를 통해 WebRTC를 코드에 직접 적용해 볼 수 있었지만 연결 흐름을 제대로 이해하지 못한 채로 구현을 하다보니 코드를 이해하는 데 어려움이 있었습니다. 그래서 별도로 WebRTC의 연결 흐름에 대해 공부한 후 다시 한 번 코드를 살펴 보니 구조가 명확히 보였습니다. 특히 특정 함수가 어떤 역할을 하는지, 어떤 순서로 배치되어야 하는지 알게 되니 코드의 전체적인 흐름을 따라가기 쉬웠습니다.
이 글은 저와 같이 WebRTC에 관심이 있거나 실무에 도입하고자 하는 분들이 실제 코드를 구현하기 전에 내부 흐름을 이해하고 전체적인 구조를 그려보는 데 도움이 되고자 작성하였습니다.
WebRTC 연결 흐름
WebRTC는 브라우저 간 직접 연결을 통해 음성, 영상, 데이터를 실시간으로 주고받을 수 있는 기술입니다. 이때 서로 연결되는 브라우저들을 피어(peer) 라고 부르며, 이러한 통신 방식을 P2P (Peer-to-Peer) 라고 합니다.
WebRTC의 작동 원리를 이해하려면 먼저 피어 간 연결이 어떻게 이루어지는지를 단계별로 살펴보는 것이 중요합니다. WebRTC는 브라우저 간 직접 통신(P2P)을 목표로 하며, 다음과 같은 과정을 거쳐 연결을 설정합니다.
1. 시그널링(Signaling): 연결 의사 교환
WebRTC는 피어 간 직접 연결을 위해 먼저 시그널링 과정을 거쳐야 합니다. 이 과정은 보통 별도의 시그널링 서버(WebSocket 등) 를 통해 이루어지며, 피어 간 “연결하고 싶다”는 의사 교환이 핵심입니다.
2. Offer 전달: A → B
A는 B에게 연결 요청의 일환으로 offer를 보냅니다. 이 offer는 SDP (Session Description Protocol) 형식으로, 코덱, 미디어 정보, 네트워크 구성 정보 등 연결 설정에 필요한 정보를 담고 있습니다.
3. Answer 전달: B → A
B는 받은 Offer를 바탕으로 연결을 수락한다는 의미의 Answer를 생성해 다시 A에게 전달합니다. 이 Answer 역시 SDP 형식이며, B 측의 연결 정보가 담겨 있습니다.
4. ICE 후보 수집: IP 후보 목록 구성
WebRTC에서 두 피어가 서로 연결되려면 상대방의 IP 주소를 알아야 합니다. 그런데 대부분의 사용자는 공유기 뒤에 있는 사설망(NAT) 환경에 있기 때문에, 단순히 로컬 IP만 가지고는 연결이 잘 되지 않습니다. 그래서 WebRTC는 ICE(Interactive Connectivity Establishment) 라는 방식을 사용해서 연결 가능한 IP와 포트 조합들을 모읍니다.
이때 수집되는 후보들을 ICE 후보(ICE candidate)라고 부르는데, 쉽게 말해 “이 IP와 포트를 사용하면 나에게 연결할 수 있어요!” 하고 상대에게 알려주는 접속 가능 후보 주소의 목록입니다. 이 후보는 로컬 IP, 공용 IP, 중계 서버 주소 등을 포함할 수 있습니다.
공용 IP를 알아내기 위해 피어는 STUN 서버에 요청을 보냅니다. STUN(Session Traversal Utilities for NAT) 서버는 단순히 클라이언트가 NAT 밖에서 어떻게 보이는지를 알려주는 역할을 합니다. 예를 들어 A가 STUN 서버에 “내 공용 IP가 뭔가요?”라고 물어보면, STUN 서버는 “당신은 xx.xx.xx.xx 로 보입니다”라고 응답합니다. 이 주소 역시 ICE 후보 중 하나로 사용됩니다. B도 동일한 방식으로 자신의 후보를 수집합니다.
하지만 때로는 공유기나 방화벽 설정으로 인해 STUN만으로는 직접 연결이 불가능한 경우도 있습니다. 이런 상황에서는 TURN(Traversal Using Relays around NAT) 서버가 사용됩니다. TURN 서버는 중간에서 데이터를 중계해주는 역할을 하며, 이 경우에는 모든 오디오/비디오 데이터가 TURN 서버를 거쳐 전달됩니다. 성능 측면에서는 직접 연결보다 느리지만, 반드시 연결이 되어야 하는 상황에서 fallback으로 사용됩니다.
이렇게 수집된 후보들은 시그널링 서버를 통해 서로 교환되고, 브라우저는 이들 중에서 가장 잘 연결되는 경로를 선택해 피어 간 연결을 수립하게 됩니다.
* B도 동일
5. ICE 후보 교환
양쪽 피어는 이렇게 수집한 ICE 후보들(로컬 IP, 공용 IP, 중계 서버 주소 등)을 시그널링 서버를 통해 서로 주고받습니다. 이 후보들은 Offer나 Answer와 함께 전달되기도 하고, 그 이후 별도로 추가로 전달되기도 합니다.
* B도 동일
6. 최적의 연결 경로 결정 및 연결 수립
브라우저는 받은 ICE 후보들 중에서 가장 연결이 잘 되는 조합을 자동으로 찾아 연결을 수립합니다. 이후에는 시그널링 서버 없이도 A ↔ B 간 직접 통신(P2P) 이 가능합니다.
7. 종료 시나리오
✅ 정상적인 종료
한쪽 피어가 연결을 종료하겠다고 명시적으로 요청하면, 상대 피어는 이를 확인하고 시그널링 서버를 통해 정상적으로 연결을 종료합니다. 이 경우 각 피어는 종료 상태를 인식하고 순차적으로 연결을 정리하게 됩니다.
❌ 비정상 종료
갑작스런 네트워크 오류나 브라우저 종료처럼 예기치 않은 상황에서는 종료 신호 없이 연결이 끊기기도 합니다. 이런 경우 시그널링 서버는 일정 시간 동안 응답이 없으면 연결이 종료된 것으로 판단하고 상태를 정리합니다.