웹소켓에 대해 알아보자

웹소켓의 장단점, 사용법, 주의사항 등을 정리했습니다

·

3 min read

웹소켓(WebSocket)은 클라이언트와 서버 간에 실시간, 양방향, 지속적인 데이터 통신을 가능하게 하는 기술입니다. HTTP 프로토콜과 달리, 웹소켓은 한 번 연결이 맺어지면 그 연결을 유지하면서 데이터를 빠르게 주고 받을 수 있습니다.

장점 and 단점

장점

  1. 양방향 통신: 클라이언트와 서버의 연결이 유지되는 동안 언제든 서로에게 데이터를 주고 받을 수 있습니다.

  2. 낮은 지연 시간: 연결이 되어있는 상태이기 때문에 데이터 교환 시 서로를 검증하는 시간이 없어서 HTTP 요청보다 지연 시간이 낮습니다.

  3. 효율적인 자원 사용: 한번의 연결 설정만으로 데이터를 주고 받을 수 있기 때문에 HTTP와 다르게 연결을 설정할 때 마다 사용되는 컴퓨팅 자원들을 아낄 수 있습니다.

단점

  1. 호환성 문제: 구형 브라우저나 일부 환경에서는 웹소켓을 지원하지 않을 수 있습니다.

  2. 스케일링 이슈: 많은 수의 연결을 관리해야 하는 경우, 서버의 부하 및 아키텍처 설계가 복잡해질 수 있습니다.

    • 예를 들어 실시간 채팅 어플리케이션을 구현할 경우 자동 재연결을 보장하거나, 메세지 순서를 보장하거나, 누락된 메세지를 재전송하도록 처리해야하는 등 고려해야 할 사항들이 많아집니다.

리액트에서 웹소켓의 기본 사용법

  • 보통 useEffect 훅 내에서 웹소켓 연결을 설정하고, 연결을 종료하는 로직을 작성합니다.

  •   import React, { useEffect } from 'react';
    
      function ChatComponent() {
          useEffect(() => {
              const ws = new WebSocket('wss://sample.com/chat');
              ws.onopen = () => {
                  console.log('Connected');
              }
              ws.onmessage = (event) => {
                  console.log('Message from sever ', event.data);
              }
    
              // 언마운트 시 연결 종료 처리
              return () => {
                  ws.close();
              }
          }, []); // 마운트 시 1회만 실행
    
          return <div> Chat </div>;
      }
    

리액트에서 웹소켓 사용 시 주의사항

  1. 재연결 로직: 네트워크 불안정, 모바일 브라우저의 사용성 등으로 인해 연결이 끊길 수 있습니다. 이를 위해 자동 재연결 로직을 구현하는 것이 좋습니다.

  2. 메모리 누수 방지: 웹소켓 이벤트 리스너 등록시에는 컴포넌트 언마운트 시 이를 제거해야 메모리 누수를 방지할 수 있습니다.

  3. 보안 프로토콜 사용: wss:// 프로토콜을 사용하여 데이터 전송 시 암호화 되도록 처리해주는 편이 좋습니다.

주의사항을 반영한 예시

import React, { useEffect, useRef } from 'react';

function ImprovedChatComponent() {
    const wsRef = useRef(null);

    useEffect(() => {
        const setWebSocket = () => {
            const ws = new WebSocket('wss://sample.com/chat');
            ws.onopen = () => {
                console.log('Connected');
            };
            ws.onclose = () => {
                console.log('Disconnected. Attempting to reconnect...');
                setTimeout(setWebSocket, 3000); // 연결 끊기면 3초뒤 재시도
            };

            // useRef를 사용하여 웹소켓 인스턴스 저장
            wsRef.current = ws;
        }

        setWebSocket();

        // 언마운트 시 웹소켓 연결 종료
        return () => {
            if (wsRef.current) {
                wsRef.current.close();
            }
        }
    }, []);

    return <div> Chat </div>;
}

onclose 이벤트 핸들러 내에서 연결이 끊어졌을 때 자동으로 재연결을 시도하는 로직을 구현했습니다.
useRef를 사용하여 웹소켓 인스턴스를 저장하고 있는데, 이렇게 함으로서 컴포넌트 생명주기에 맞춰 적절하게 웹소켓 연결과 종료를 할 수 있어서 자원 낭비를 막을 수 있습니다.

마치며

운영하는 서비스에서 웹소켓 관련 코드를 수정하다보니 웹소켓에 대해 잘 모르고 있다는 점을 반성하며 내용을 정리하는 글을 써봤습니다. 웹소켓의 가장 어려운 부분은 여러가지 연결에 대한 설계일 것이라고 판단되지만, 클라이언트 단에서도 리액트 컴포넌트의 생명주기에 맞춰서 세심하게 설정해줘야 한다는 점을 알 수 있었습니다.