WebRTC

[์›๋ณธ ๋งํฌ]

WebRTC๋Š” Web Real-Time Communication์˜ ์ค€๋ง๋กœ, ๋ธŒ๋ผ์šฐ์ €๋“ค์ด ์„œ๋ฒ„๋ฅผ ๊ฑฐ์น˜์ง€ ์•Š๊ณ  P2P๋กœ ํ†ต์‹ ์„ ๊ฝ‚๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋Š” ์›นํ‘œ์ค€ ํ”„๋กœํ† ์ฝœ ์ค‘ ํ•˜๋‚˜๋‹ค.

์„œ๋ฒ„๋ฅผ ๊ฑฐ์น˜์น˜ ์•Š์œผ๋‹ˆ ๋” ๋น ๋ฅด๊ณ  ์ฆ‰๊ฐ์ ์ธ ํ†ต์‹  ์„œ๋น„์Šค๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค.

์ด๋ฅผํ…Œ๋ฉด ์คŒ(Zoom) ๊ฐ™์€ ์›น ๊ธฐ๋ฐ˜์˜ ํ™”์ƒ ์ฑ„ํŒ… ์„œ๋น„์Šค๋“ค์ด ์ด ๊ธฐ์ˆ ์„ ํ†ตํ•ด ๋งŒ๋“ค์–ด์ง„๋‹ค.

๊ตฌ๊ธ€์ด 2011๋…„์— ์ฒ˜์Œ ์˜คํ”ˆ์†Œ์Šค๋กœ ๋ฐœํ‘œํ•ด์„œ ํผ์ง€๊ธฐ ์‹œ์ž‘ํ–ˆ๊ณ , ํ˜„์žฌ๋Š” ์ƒ๋‹น์ˆ˜์˜ ๋ธŒ๋ผ์šฐ์ €์—์„œ ์ง€์›๋œ๋‹ค.

๋Œ€๋ถ€๋ถ„์€ ์˜์ƒ์ด๋‚˜ ์˜ค๋””์˜ค ๋“ฑ์„ ์ฃผ๊ณ ๋ฐ›๋Š”๋ฐ ์‚ฌ์šฉํ•˜์ง€๋งŒ, ํ…์ŠคํŠธ ๋“ฑ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ๊ณ ๋ฐ›์„ ๋•Œ๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.




๊ตฌ์กฐ

๋ธŒ๋ผ์šฐ์ €๋ผ๋ฆฌ ๊ณง์žฅ ํ†ต์‹ ์„ ํ•  ์ˆ˜ ์žˆ๊ธด ํ•˜์ง€๋งŒ, ๊ทธ๋ž˜๋„ ์•„๋ฌด๊ฒƒ๋„ ์—†์ด ํด๋ผ์ด์–ธํŠธ๋ผ๋ฆฌ ์„œ๋กœ์˜ ์ฃผ์†Œ๋ฅผ ์•Œ๊ธฐ๋ž€... ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค.
์—ฌ๊ธฐ์„œ๋„ ์„œ๋ฒ„๋Š” ์ค‘์š”ํ•˜๋‹ค. ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ํ†ต์‹ ์„ ์—ฐ๊ฒฐํ•  ๋‹ค๋ฅธ ํด๋ผ์ด์–ธํŠธ์˜ ์ •๋ณด๋ฅผ ์ค˜์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

๊ทธ๋ž˜์„œ ์ค‘๊ฐ„์— Stun Server๋ผ๋Š” ์ค‘๊ณ„์ž๋ฅผ ๋‘๊ณ , ์„œ๋กœ๊ฐ„์˜ IP๋ฅผ ์•Œ์•„๋‚ผ ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค.

https://www.techtarget.com/searchunifiedcommunications/definition/WebRTC-Web-Real-Time-Communications

์ฃผ์š”ํ•œ ํ•จ์ˆ˜๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.
RTCPeerConnection: P2P ์—ฐ๊ฒฐ์„ ๋งŒ๋“ค๊ณ  ํƒ์ƒ‰ํ•˜๋Š” ๊ฐ์ฒด
RTCSessionDescription: P2P ์—ฐ๊ฒฐ์‹œ ๊ฐ ์—”๋“œํฌ์ธํŠธ์˜ ์—ฐ๊ฒฐ ์ •๋ณด





Stun ์„œ๋ฒ„์™€ RTCPeerConnection


Stun ์„œ๋ฒ„๋Š” ํด๋ผ์ด์–ธํŠธ์˜ public IP์™€ ํฌํŠธ ๋“ฑ์„ ์ถ”์ถœํ•ด์ฃผ๋Š” ์ค‘๊ฐœ ์„œ๋ฒ„๋‹ค. ์›๋ž˜ ๋กœ์ปฌ ๋‚ด์—์„œ๋Š” ๋กœ์ปฌ IP๋Š” ๋ฐ”๋กœ ์•Œ ์ˆ˜ ์žˆ์ง€๋งŒ, public IP๋Š” ์•Œ๊ธฐ๊ฐ€ ์‰ฝ์ง€ ์•Š์„ ์ˆ˜ ์žˆ๋‹ค.

๊ทธ๋ƒฅ ๋กœ์ปฌํ…Œ์ŠคํŠธ๋งŒ ํ• ๋•Œ๋Š” ์—†์–ด๋„ ๋˜์ง€๋งŒ, ์‹ค์‚ฌ์šฉํ• ๋•Œ๋Š” ๊ฑฐ์˜ ํ•„์ˆ˜๋กœ ์‚ฌ์šฉํ•œ๋‹ค.

๊ฐ„๋‹จํ•˜๊ฒŒ ๋„์šฐ๋Š” ๋ฐฉ๋ฒ•์€ coturn ๋“ฑ์˜ ์™„์„ฑ๋œ ํ”„๋กœ๊ทธ๋žจ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด๋‹ค.
์šฐ๋ถ„ํˆฌ์—์„œ๋Š” ๊ทธ๋ƒฅ ํŒจํ‚ค์ง€๋งค๋‹ˆ์ €๋กœ ๋ฐ”๋กœ ๊น”๊ณ  ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

sudo apt-get update
sudo apt-get install coturn -y
sudo systemctl kill coturn
sudo turnserver --log-file stdout

์ด๋ ‡๊ฒŒ ์‹คํ–‰๋˜๋ฉด ๋œ๋‹ค.
์Šคํ„ด์„œ๋ฒ„๋Š” UDP 3478 ํฌํŠธ๋กœ ๊ฐœ๋ฐฉ๋œ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๋‹ค์Œ๊ณผ ๊ฐ™์ด PeerConnection ์ƒ์„ฑ์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

      const config = {
        iceServers: [{ urls: "stun:54.180.105.67" }],
      };

      const localConnection = new RTCPeerConnection();



์‹œ๊ทธ๋„๋ง(Signaling) ์„œ๋ฒ„

WebRTC์— ํ•„์š”ํ•œ ๋˜ ํ•˜๋‚˜์˜ ๋ถ€๊ฐ€์š”์†Œ๊ฐ€ ์‹œ๊ทธ๋„๋ง ์„œ๋ฒ„๋‹ค.
์Šคํ„ด์„œ๋ฒ„๊ฐ€ ๊ทธ๋ƒฅ IP๋งŒ ๋Œ๋ ค์ฃผ๋Š” ๊ฐ„๋‹จํ•œ ์ž‘์—…๋งŒ ํ–ˆ๋‹ค๋ฉด, ์ด๊ฑด ์ง์ ‘ ๊ฐ๊ฐ์˜ Peer์™€ Peer๋ฅผ ์ง์ ‘ ์—ฐ๊ฒฐํ•ด์ฃผ๋Š” ์—ญํ• ์„ ๋‹ด๋‹นํ•œ๋‹ค.
์ƒˆ๋กœ์šด Peer๊ฐ€ ๋“ค์–ด์˜ฌ๋•Œ๋งˆ๋‹ค ๊ธฐ์กด์˜ Peer์— Broadcast ๋“ฑ์„ ํ•ด์ค˜์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์›น์†Œ์ผ“์œผ๋กœ ๊ตฌํ˜„์„ ๋งŽ์ด ํ•œ๋‹ค.

์•„๋ž˜๋Š” ๊ทธ์— ๋Œ€ํ•œ ๊ฐ„๋‹จํ•œ ๊ตฌํ˜„๋ก€๋‹ค.

const Express = require("express");
const fs = require("fs");
const WebSocket = require("ws");

const app = Express();

app.get("/", (req, res) => {
  const html = fs.readFileSync("./index.html", "utf-8");
  res.send(html);
});

const port = 8080;
const wss = new WebSocket.Server({ port });

wss.on("connection", (socket) => {
  console.log("์ƒˆ๋กœ์šด ์—ฐ๊ฒฐ์ด ์ƒ์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.");

  // offer๋ฅผ ์ˆ˜์‹ ํ•˜๊ณ  ๋‹ค๋ฅธ ํด๋ผ์ด์–ธํŠธ๋กœ ์ „๋‹ฌ
  socket.on("offer", (offer) => {
    console.log("์ƒˆ๋กœ์šด offer๋ฅผ ์ˆ˜์‹ ํ•˜์˜€์Šต๋‹ˆ๋‹ค.");
    socket.broadcast.emit("offer", offer);
  });

  // answer๋ฅผ ์ˆ˜์‹ ํ•˜๊ณ  ๋‹ค๋ฅธ ํด๋ผ์ด์–ธํŠธ๋กœ ์ „๋‹ฌ
  socket.on("answer", (answer) => {
    console.log("์ƒˆ๋กœ์šด answer๋ฅผ ์ˆ˜์‹ ํ•˜์˜€์Šต๋‹ˆ๋‹ค.");
    socket.broadcast.emit("answer", answer);
  });

  // ICE candidate๋ฅผ ์ˆ˜์‹ ํ•˜๊ณ  ๋‹ค๋ฅธ ํด๋ผ์ด์–ธํŠธ๋กœ ์ „๋‹ฌ
  socket.on("candidate", (candidate) => {
    console.log("์ƒˆ๋กœ์šด ICE candidate๋ฅผ ์ˆ˜์‹ ํ•˜์˜€์Šต๋‹ˆ๋‹ค.");
    socket.broadcast.emit("candidate", candidate);
  });

  // ํด๋ผ์ด์–ธํŠธ์™€ ์—ฐ๊ฒฐ์ด ๋Š์–ด์งˆ ๋•Œ
  socket.on("disconnect", () => {
    console.log("์—ฐ๊ฒฐ์ด ์ข…๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.");
  });
});

app.listen(5500, () => {
  console.log("Server started on port 5500");
});



P2P ์—ฐ๊ฒฐ

์šฐ์„  ๋‹ค์Œ๊ณผ ๊ฐ™์ด Peer Connection ๊ตฌ์„ฑ์„ ์ƒ์„ฑํ•ด์•ผ ํ•œ๋‹ค.

localConnection = new RTCPeerConnection();
sendChannel = localConnection.createDataChannel("sendChannel");

remoteConnection = new RTCPeerConnection();
remoteConnection.ondatachannel = receiveChannelCallback;

๊ทธ ๋‹ค์Œ์—๋Š” RTCPeerConnection๋ฅผ ์ด์šฉํ•ด์„œ Peer๋ผ๋ฆฌ Offer์™€ Answer๋ผ๋Š” ๋ฉ”์‹œ์ง€๋ฅผ ๊ตํ™˜ํ•œ๋‹ค.
์ด๋Ÿฐ ์‹์œผ๋กœ ๋ณด์ธ๋‹ค.

์ด๊ฒƒ๋„ ๋ณดํ†ต ์‹œ๊ทธ๋„๋ง ์„œ๋ฒ„๋ฅผ ํ†ตํ•ด ์ฃผ๊ณ ๋ฐ›๋Š”๋‹ค.

๊ทธ ๋‹ค์Œ์—๋Š” ICE Candidate๋ผ๊ณ  ํ•˜๋Š” ๊ฐ Peer์˜ ๋„คํŠธ์›Œํฌ ์ฃผ์†Œ ์ •๋ณด๋ฅผ ๊ตํ™˜ํ•ด์„œ ์—ฐ๊ฒฐ ์ž‘์—…์„ ๋งˆ๋ฌด๋ฆฌ์ง“๋Š”๋‹ค.
๊ทธ๋Ÿฌ๋ฉด ๋ฐ์ดํ„ฐ ์ฑ„๋„ ๋“ฑ์„ ์‚ฌ์šฉํ•ด์„œ ์ง€์†์ ์œผ๋กœ P2P ํ†ต์‹ ์„ ์ฃผ๊ณ ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค.


๊ทธ๋ ‡๋‹ค.



์ฐธ์กฐ
https://developer.mozilla.org/ko/docs/Web/API/WebRTC_API
https://acstory.tistory.com/534
https://github.com/coturn/coturn
https://github.com/aljanabim/simple_webrtc_signaling_server
https://github.com/mdn/samples-server/blob/master/s/webrtc-simple-datachannel/main.js