TT Lab
시작하기
배우기 러닝패스 코스

실시간 통신 — WebSocket·gRPC 스트리밍·WebRTC

WebRTC — 시그널링은 직접 만든다

TT Lab 에서 이어서 보기

한 줄 요약

WebRTC 는 연결을 맺는 방법을 정하지 않으므로 SDP 를 건넬 시그널링을 직접 만들고, ICE 로 길을 찾고, DTLS 로 열쇠를 나눈 뒤, SRTP 로 미디어를, SCTP 로 데이터 채널을 나릅니다.

왜 이게 필요했나

두 기기가 서로 직접 말하게 하려면 풀어야 할 문제가 셋입니다. 서로의 주소와 능력을 어떻게 알리나(시그널링), 둘 다 NAT 뒤에 있을 때 어떤 길로 닿나(ICE·STUN·TURN), 그 길 위의 데이터를 어떻게 보호하나(DTLS-SRTP). RFC 8825 가 개괄하는 WebRTC 는 뒤의 둘은 정했지만 첫째는 일부러 비워 두었습니다. JSEP(RFC 9429) 는 브라우저가 SDP 제안과 응답을 만들어 주는 방법을 정할 뿐, 그것을 상대에게 어떻게 건넬지는 애플리케이션에 맡깁니다. 그래서 거의 모든 서비스가 WebSocket 같은 작은 시그널링 서버를 따로 둡니다.

연결이 맺어지기까지 세 층

WebRTC 는 두 기기가 서로 직접 말하려고 풀어야 할 문제를 셋으로 나눈다. 주소와 능력을 알리는 일, NAT 뒤에서 길을 찾는 일, 그 길 위의 데이터를 보호하는 일이다. 본문 순서대로 옮겼다.

  1. 시그널링: SDP 를 건넬 길을 직접 만든다제안하는 쪽이 createOffer 로 SDP 를 만들고, 응답하는 쪽은 받은 제안을 setRemoteDescription 에 넣고 createAnswer 로 답한다. 이 규격은 SDP 를 만드는 방법만 정하고 건네는 방법은 애플리케이션에 맡겨서, 거의 모든 서비스가 WebSocket 같은 작은 시그널링 서버를 따로 둔다.
  2. ICE: 후보를 모아 짝을 지어 확인한다가능한 주소를 모두 모으고 짝을 지어 연결 확인을 해 본 뒤 되는 짝 가운데 하나를 고른다. 후보는 host, srflx, relay 세 종류이다.
  3. DTLS 로 열쇠를 나누고 SRTP 와 SCTP 로 나른다길이 정해지면 그 위에서 DTLS 핸드셰이크를 한다. 상대 인증서의 해시가 시그널링으로 받은 a=fingerprint 와 같아야 한다. 미디어 키는 이 핸드셰이크에서 뽑아 SRTP 에 쓰고, 데이터 채널은 DTLS 위의 SCTP 로 흐른다.

여기서 구분할 것 WebRTC 가 일부러 비워 둔 것은 첫째 문제뿐이고 뒤의 둘은 규격이 정했다. 이 도식은 본문의 설명 순서를 단순하게 옮긴 것이다. 후보를 다 모은 뒤에 SDP 를 보내는 방식과 모이는 대로 따로 보내는 trickle ICE 에 따라 후보가 오가는 시점은 달라진다.

잠깐, 예측해 보세요 createOffer 를 부르기 전에 오디오 트랙도 데이터 채널도 추가하지 않았다. 이때 만들어진 제안 SDP 는 어떤 모양일까?

설명 확인 · 채점 없는 자가 점검

m= 줄이 없는 빈 제안이 된다. 본문은 제안하는 쪽이 보낼 것(오디오 트랙, 데이터 채널)을 먼저 정한 뒤 createOffer 로 SDP 를 만든다고 설명하고, SDP 에는 매체마다 m= 줄이 담긴다고 한다.

근거 문서

어떻게 동작하나

SDP 제안과 응답. 제안하는 쪽은 무엇을 보낼지(오디오 트랙, 데이터 채널)를 정한 뒤 createOffer 로 SDP 를 만듭니다. 보낼 것을 정하지 않으면 m= 줄이 없는 빈 제안이 됩니다. SDP 에는 매체마다 m= 줄, 코덱(a=rtpmap), ICE 자격(a=ice-ufrag·a=ice-pwd), DTLS 인증서의 지문(a=fingerprint), DTLS 역할(a=setup:actpass·active·passive), 그리고 후보(a=candidate)가 담깁니다. 응답하는 쪽은 받은 제안을 setRemoteDescription 에 넣고 createAnswer 로 답합니다.

ICE 후보. ICE(RFC 8445) 는 가능한 주소를 모두 모아(후보 수집) 짝을 지어 연결 확인을 해 보고, 되는 짝 가운데 하나를 고릅니다. 후보는 세 종류입니다.

종류 어디서 오나 뜻
host 자기 인터페이스 같은 망 안이면 이것으로 충분하다
srflx STUN 서버가 본 주소 NAT 가 바꿔 준 바깥 주소
relay TURN 서버가 빌려준 주소 직접 닿지 않을 때 서버가 대신 나른다

STUN(RFC 8489) 서버는 Binding 요청에 "내가 본 당신의 주소" 를 XOR-MAPPED-ADDRESS 로 돌려줄 뿐 데이터를 나르지 않습니다. 대칭 NAT 나 UDP 가 막힌 망에서는 그 주소로도 닿지 않으므로 TURN(RFC 8656) 서버가 중계 주소를 빌려주고 모든 데이터를 대신 나릅니다. TURN 은 대역폭 비용이 들지만, 없으면 일부 사용자는 아예 연결되지 않습니다. UDP 가 막힌 곳을 위해 TCP·TLS 443 으로도 TURN 을 엽니다. 후보를 다 모은 뒤에 SDP 를 보내는 방식과, 모이는 대로 따로 보내는 trickle ICE 가 있습니다. 실습의 aiortc 는 앞의 방식이라, 닿지 않는 STUN 서버를 설정하면 그 응답을 기다리느라 제안이 몇 초 늦어집니다.

DTLS-SRTP 와 SCTP. 길이 정해지면 그 위에서 DTLS 핸드셰이크를 합니다. 상대가 보여 준 인증서의 해시가 시그널링으로 받은 a=fingerprint 와 같아야 하고, 이것이 중간자 공격을 막습니다. RFC 8827 은 모든 미디어를 암호화하도록 요구하고, 미디어 키는 DTLS 핸드셰이크에서 뽑아 SRTP 에 씁니다(RFC 5764). 데이터 채널은 DTLS 위의 SCTP 로 흐르고(RFC 8831), 채널마다 순서 보장 여부와 재전송 한도(maxRetransmits)나 수명(maxPacketLifeTime)을 따로 정할 수 있습니다. 음성 프레임처럼 20ms 뒤에는 쓸모없는 데이터는 순서 없이, 재전송 없이 보내는 편이 낫습니다.

미디어 트랙. 오디오는 RTP 로 흐릅니다. RFC 7874 는 WebRTC 가 반드시 구현할 오디오 코덱으로 Opus 와 G.711 을 정하고, RFC 7587 은 Opus 를 입력 표본율과 상관없이 SDP 에 opus/48000/2 로 적게 합니다.

현장에서 만나는 모습

지터와 손실. 음성은 재전송을 기다릴 여유가 없어서 받는 쪽이 지터 버퍼로 도착 간격의 흔들림을 흡수하고, 잃은 프레임은 앞뒤 소리로 메웁니다(손실 은닉). 버퍼가 크면 끊김은 줄지만 모든 소리가 그만큼 늦습니다. ITU-T G.114 는 한 방향 지연이 150ms 이하면 대부분의 대화에 무리가 없다고 봅니다. "회사 망에서만 연결이 안 된다" 는 대개 UDP 가 막혔는데 TURN 이 없거나 TURN 이 UDP 로만 열린 경우이고, "연결까지 5초" 는 닿지 않는 STUN 을 기다리는 경우입니다.

STUN 은 주소만 알려 주고 TURN 은 데이터를 대신 나른다

NAT 뒤에서 닿는 길을 만드는 두 서버는 하는 일이 다르다. 후보 종류 가운데 srflx 와 relay 가 각각 어디서 오는지와 함께 견준다.

  • STUN: 내가 본 당신의 주소를 알려 준다Binding 요청에 내가 본 당신의 주소를 XOR-MAPPED-ADDRESS 로 돌려줄 뿐 데이터를 나르지 않는다. 그 주소가 NAT 가 바꿔 준 바깥 주소이고 srflx 후보가 된다.
  • TURN: 중계 주소를 빌려주고 데이터를 대신 나른다대칭 NAT 나 UDP 가 막힌 망처럼 STUN 이 알려 준 주소로도 닿지 않을 때 쓴다. 서버가 빌려준 주소가 relay 후보이다. 대역폭 비용이 들지만 없으면 일부 사용자는 아예 연결되지 않는다. UDP 가 막힌 곳을 위해 TCP 와 TLS 443 으로도 연다.

여기서 구분할 것 같은 망 안이면 자기 인터페이스 주소인 host 후보로 충분하다. 본문은 회사 망에서만 안 되는 경우를 UDP 가 막혔는데 TURN 이 없거나 TURN 이 UDP 로만 열린 경우로 든다. 이 대응은 레슨 본문의 서술이다.

잠깐, 예측해 보세요 제안을 만드는 데 5초가 걸린다. 설정해 둔 STUN 서버 주소는 닿지 않는 곳이다. 본문 기준으로 왜 제안이 늦어질까?

설명 확인 · 채점 없는 자가 점검

본문의 실습에서 쓰는 aiortc 는 후보를 다 모은 뒤에 SDP 를 보내는 방식이라, 닿지 않는 STUN 서버의 응답을 기다리느라 제안이 몇 초 늦어진다. 모이는 대로 따로 보내는 trickle ICE 도 있다고 하지만 그때 지연이 어떻게 달라지는지는 본문이 적지 않았다.

근거 문서

다음 실습에서 할 것

WebSocket 시그널링 서버를 만들고, aiortc 로 응답 피어와 제안 피어를 만들어 기준 피어와 데이터 채널로 메시지를 주고받습니다. 채널을 순서 없고 재전송 없는 것으로 바꾸고, 같은 파드 안의 STUN 서버로 srflx 후보가 생기는 모습과 막힌 STUN 이 수집을 늦추는 모습을 잽니다.