WebRTC 구성하기

솔다·2023년 2월 4일
0

Javascript로 WebRTC 구성하기

자바스크립트로 WebRTC를 구성하기 위해서는 우선, 우리는 이 컴퓨터들이 빠르게 통신을 할 수 있도록, socket 통신을 하도록 만들어줘야 한다.

물론, javascript에서도 기본적으로 websocket 기능을 제공하고 socket 통신을 하도록 만들어줄 수 있다.

node.js를 이용 하면, 내부적으로 websocket 통신을 하는 서버를 구성할 수 있지만, 몇가지 단점이 있다.

우리에게는 이제 너무나도 친숙한 노마드코더 강의를 참고해서 아래의 예제를 작성하였으니, 더 궁금한 내용이 있는 분들은 강의를 직접 보기를 추천한다.

const messageList = document.querySelector("ul");
const nickForm = document.querySelector("#nick");
const messageForm = document.querySelector("#message");
const socket = new WebSocket(`ws://${window.location.host}`);

socket.addEventListener("open", () => {
    console.log("Connected with Server");
})

socket.addEventListener("message", (message) => {
    const li = document.createElement("li");
    li.innerText = message.data;
    messageList.append(li);
});

socket.addEventListener("close", ()=> {
    console.log("Disconnected from Server");
});

function makeMessage(type, payload) {
    const msg = {type, payload};
    return JSON.stringify(msg);
}

function handleSubmit(event){
    event.preventDefault();
    const input = messageForm.querySelector("input");
    socket.send(makeMessage("new_message", input.value));
    const li = document.createElement("li");
    li.innerText = `You: ${input.value}`;
    messageList.append(li);
    input.value = "";
}

function handleNickSubmit(event){
    event.preventDefault();
    const input = nickForm.querySelector("input");
    socket.send(makeMessage("nickname", input.value));
}

messageForm.addEventListener("submit", handleSubmit);
nickForm.addEventListener("submit", handleNickSubmit);

코드를 전부 뜯어보면 좋겠지만, 몇 가지 특색만 좀 짚어보고 갈까 한다. makeMessage()함수를 보자. 이 함수를 보면, typepayload를 인자로 받아서 하나의 msg 로 만들어 준 다음에 JSON.stringify()로 json 방식으로 만들어서 리턴해주는 것을 알 수 있다.

이 함수는 어디에서 호출 되는가?
submit되는 부분에서 호출되고 있다. 정확히는 handleSubmit()함수와 handleNickSubmit()함수에서 socket.send()의 인자로 넣어지고 있다.

왜?
왜 이런방식으로 넣는지를 알아야 하는데, 이는 바로 기본적으로 제공되는 socket 통신의 한계 때문이다.

Websocket 에서는 데이터를 오직 String 형태로만 주고받을 수 있다.

이런 한계점 때문에, 단순 txt msg는 손쉽게 구현가능하고, 서버에서 처리하기도 매우 쉽지만, 기능을 복잡하게 만들기 위해서는 매우매우 복잡하다는 것을 생각해볼 수 있다.

몇가지 기능을 만든다고 생각해보자. 만일, 채팅방을 만든다고 치자. live한 특징으로 연결되어 메신저를 주고 받는다고 가정해보자.

여러명과 대화를 하기 위해서는 채팅 내용 뿐만이 아니라, 말한 사람을 명확하게 해주는 구분이 필요할 것이다. 또한, 모든 사람이 하나의 채팅방에 있는것도 말이 안되므로, 각각 원하는 채팅방에 들어가야 할 것이다.

서버는 단순하게 이런 데이터를 string으로만 받을 수 있다. 매우 긴 string 형태로 매번 변환을 해서 만들어 줘야 한다는 불편함이 있을 거다. 그럼에도 불구하고 기능을 구현해볼 수 있지만, 우리는 늘 그래왔듯이 답을 찾는다.

socket.io는 최고다.

socket.io를 다운받고 import 해주자. socket.io는 이미 매우 많은 곳에서 사용되고 있으며 검증된 모듈이다.

그리고 우리가 채팅방을 만든다고 가정했을때 고려해줘야 하는 모든 것들이 기본기능만으로 처리가 된다.

const socket = io();

const welcome = document.getElementById("welcome");
const form = welcome.querySelector("form");
const room = document.getElementById("room");

room.hidden = true;

let roomName;

function showRoom() {
    welcome.hidden = true;
    room.hidden = false;
    const h3 = room.querySelector("h3");
    h3.innerText = `Room ${roomName}`;
}

function handleRoomSubmit(event) {
    event.preventDefault();
    const input = form.querySelector("input");
    socket.emit("enter_room", input.value, showRoom);
    roomName = input.value;
    input.value = ""
}

form.addEventListener("submit", handleRoomSubmit);

function addMessage(message) {
    const ul = room.querySelector("ul");
    const li = document.createElement("li");
    li.innerText = message;
    ul.appendChild(li);
}


socket.on("welcome", () => {
  addMessage("someone joined!");
});

간단한 채팅방을 나눈다고 했을때, 현재 위의 코드는 room별로 접속한 사람들을 구분하며, 처음 방에 들어오는 순간 메세지를 보내주고 있는코드이다.

socket.on() 하나만으로도 어떤 종류의 요청이 왔는지 쉽게 파악할 수 있다. 그리고 socket.io의 강력함이 드러나보이는 부분이 또 있는데, 기본으로 제공하는 기능이 매우 많다는 것이다. 이는 서버단 코드에 몇가지 예시가 포함되어있다.

import http from "http";
import { Server } from "socket.io";
import express from "express";

const app = express();

app.set("view engine", "pug");
app.set("views", __dirname + "/views");
app.use("/public", express.static(__dirname + "/public"));
app.get("/", (_, res) => res.render("home"));
app.get("/*", (_, res) => res.redirect("/"));

const httpServer = http.createServer(app);
const wsServer = new Server(httpServer);

wsServer.on("connection", (socket) => {
    socket.onAny((event) => {
        console.log(`Socket Event: ${event}`);
    });
    socket.on("enter_room", (roomName, done) => {
        socket.join(roomName);
        done();
        socket.to(roomName).emit("welcome");
    });
});

const handleListen = () => console.log(`Listening on http://localhost:3000`);
httpServer.listen(3000, handleListen);

코드를 보면, socket.to().emit()가 있는데, emit()을 통해서 전에 send()를 했던 것처럼 데이터를 보내줄 수 있고, to()를 통해서 나를 제외한 같은 room에 있는 사람들을 대상으로 송출할 수 있다.

또한, 놀라운 점은 room개념이 이미 기본적으로 가지고 있다는 사실이다. 서버단 코드에서는 없지만, 기본적으로 페이지에 접속하면 socket["id"]를 이미 배정한 상태로 들어와 있다는 것이다.

그래서 socket.join(newRoomName) 을 실행해주면 새로운 id를 가진 room으로 진입하게 된다.

이외에도 많은 기능들이 포함되어 있으니 공식문서를 읽어보면서 추가 학습을 할 예정이다. 다음에는 채팅방을 마저 완성하고 본격적으로 카메라 통신기능을 활용해볼 예정이다.

0개의 댓글