[Node] Socket.io 활용 WebRTC

2024. 8. 24. 15:36·JavaScript/Node

가장 최근 진행한 프로젝트 당시 1:1 비대면 화상진료 기능을 맡았다.

 

해당 기능을 구현하기 위해서 Socket.io와 WebRTC를 사용해 보고자 했다.

Socket.io는 클라이언트와 서버 간의 실시간 양방향 통신을 처리하는 데 사용되며, WebRTC는 브라우저 간 P2P(피어 투 피어) 연결을 통해 오디오, 비디오 및 데이터를 실시간으로 전송할 수 있게 해준다.

 

WebSocket이 아닌 Socket.io를 사용한 이유는 

Socket.io는 소켓 연결이 끊어지면 자동으로 재연결을 시도하는 기능과 WebSocket뿐만 아니라 폴링이나 언폴링 등의 다양한 연결 방식을 가지고 있어 해당 클라이언트에 가장 잘 맞는 연결 방식을 동적으로 네트워크 환경 지원 여부에 따라 선택을 해준다.

 

또한, 네임 스페이스와 방 기능을 내장하고 있어 편리하게 사용이 가능하다.

 


 

const wsServer = new Server(httpsServer, {
    cors: {
        origin: ["https://admin.socket.io"],
        credentials: true
    }
});

Socket.io를 사용하여 WebSocket 서버를 HTTPS 서버와 연결하고, CORS 설정을 통해 특정 도메인에서의 요청을 허용하고 있다.

 

socket.on("enter_room", (roomName, done) => {
    socket.join(roomName);
    done();
    socket.to(roomName).emit("welcome", socket.nickname, countRoom(roomName));
    wsServer.sockets.emit("room_change", publicRooms());
});

 

사용자가 특정 채팅방에 들어가면 enter_room 이벤트를 통해 방에 참여하고, 해당 방에 있는 다른 사용자에게 메시지를 보낸다. room_change 이벤트를 통해 방의 상태를 업데이트한다.

 

socket.on("join_room", (roomName) => {
    socket.join(roomName);
    socket.to(roomName).emit("welcome");
});
socket.on("offer", (offer, roomName) => {
    socket.to(roomName).emit("offer", offer);
});
socket.on("answer", (answer, roomName) => {
    socket.to(roomName).emit("answer", answer);
});
socket.on("ice", (ice, roomName) => {
    socket.to(roomName).emit("ice", ice);
});

 

 

join_room 이벤트를 통해 사용자가 방에 참여할 때, 그 사실을 방의 다른 사용자에게 알린다. (카카오톡 단체방에서 "**님이 들어오셨습니다." 를 생각하면 된다.)

offer, answer, ice 이벤트는 WebRTC 연결 설정에 사용된다. 이들은 각각 SDP offer/answer 교환과 ICE 후보 정보 교환에 사용된다.

 

function handleChatRoomSubmit(event) {
    event.preventDefault();
    const input = chatForm.querySelector("input");
    socket.emit("enter_room", input.value, showRoom );
    chatRoomName = input.value;
    input.value="";
}

function handleNicknameSubmit(event){
    event.preventDefault();
    const input = room.querySelector('#name input');
    const value = input.value;
    socket.emit("nickname", input.value);
    alert(input.value + " 닉네임 설정")
}

 

 

handleChatRoomSubmit: 사용자가 특정 채팅방에 들어갈 때 서버에 enter_room 이벤트를 전송한다.

handleNicknameSubmit: 사용자가 닉네임을 설정하면 서버에 nickname 이벤트를 전송한다.

 

async function getMedia(deviceId){
    const initialConstraints = {
        audio: true,
        video: { facingMode: "user" },
    };
    const cameraConstraints = {
        audio: true,
        video: { deviceId: { exact: deviceId } },
    };
    try{
        myStream = await navigator.mediaDevices.getUserMedia(
            deviceId ? cameraConstraints : initialConstraints
        );
        myFace.srcObject = myStream;
        if (!deviceId) {
            await getCameras();
        }
    } catch(e){
        console.log(e);
    }
}

function handleMuteClick(){
    myStream.getAudioTracks()
        .forEach((track) => (track.enabled = !track.enabled));
    if (!muted){
        muteBtn.innerText = "소리켜기";
        muted = true;
    } else {
        muteBtn.innerText = "음소거";
        muted = false;
    }
}

 

getMedia: 사용자의 카메라와 마이크 스트림을 가져온다. deviceId가 주어지면 특정 카메라를 선택하고, 그렇지 않으면 기본 카메라를 사용한다.

 

function makeConnection(){
    myPeerConnection = new RTCPeerConnection();
    myPeerConnection.addEventListener("icecandidate", handleIce);
    myPeerConnection.addEventListener("addstream", handleAddStream);
    myStream.getTracks().forEach((track) => myPeerConnection.addTrack(track, myStream));
}

 

makeConnection: WebRTC P2P 연결을 설정하고, ICE 후보와 스트림 이벤트를 처리할 핸들러를 추가한다.

 

socket.on("welcome", async () => {
    const offer = await myPeerConnection.createOffer();
    myPeerConnection.setLocalDescription(offer);
    socket.emit("offer", offer, roomName);
});

socket.on("offer", async (offer) => {
    myPeerConnection.setRemoteDescription(offer);
    const answer = await myPeerConnection.createAnswer();
    myPeerConnection.setLocalDescription(answer);
    socket.emit("answer", answer, roomName);
});

socket.on("answer", answer => {
    myPeerConnection.setRemoteDescription(answer);
});

socket.on("ice", ice => {
    myPeerConnection.addIceCandidate(ice);
});

서버로부터 들어오는 offer, answer, ice 이벤트를 처리한다. WebRTC 연결을 통해 P2P 연결을 설정한다.

저작자표시 (새창열림)

'JavaScript > Node' 카테고리의 다른 글

[Node] 암호화(feat. bcrypt)  (0) 2024.07.25
[Node] session  (3) 2024.07.24
[Node] Node.js?  (2) 2024.07.17
'JavaScript/Node' 카테고리의 다른 글
  • [Node] 암호화(feat. bcrypt)
  • [Node] session
  • [Node] Node.js?
whkim98
whkim98
꾸준히 내 것으로 만드는 게시글을 작성하자
  • whkim98
    내 일기장
    whkim98
  • 전체
    오늘
    어제
    • 분류 전체보기
      • JAVA
      • JavaScript
        • Node
        • React
      • PYTHON
      • GitHub
      • DJANGO
      • Project
        • Insty
        • ERP
      • Cloud
        • NAVER CLOUD Web DevOps
        • Public
      • 자격증
        • SQLD
        • 정보처리기사
        • ADsP
        • 리눅스마스터
        • AWS
      • 코딩테스트
        • 프로그래머스 Lv0
        • 프로그래머스 Lv1
      • Spring
      • Tools
        • Postman
        • eGov
      • WEB
      • CS
      • DevOps
  • 블로그 메뉴

    • 홈
    • GitHub
    • 방명록
  • 링크

    • GitHub
  • 공지사항

  • 인기 글

  • 태그

    django
    CORS
    Tomcat
    Postman
    javascript
    AWS
    jsp
    해시 암호화
    spring
    RDBMS
    web
    Python
    node
    eGov
    js
    html
    annotation
    SQLD
    프로그래머스
    Java
    정보처리기사
    AdSP
    코딩테스트
    코테
    React
    github
    Cloud
    git
    gitbash
    코딩
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.0
whkim98
[Node] Socket.io 활용 WebRTC
상단으로

티스토리툴바