Network Protocol - Web Socket

박상준

2025년 02월 25일

1

Network
Web Socket

갑자기 통신 프로토콜?

사실 갑자기는 아니다. 웹개발자에게 있어서 네트워크 프로토콜은 필수적인 요소이다. 왜냐하면 데이터를 주고 받는 수단이기 때문이다. 그래서 전부터 한번 정리해보자는 생각은 가지고 있었지만 이것저것 하다보니 너무 미뤄져서 하게 되는 것도 있다.

그리고 이번에 코인 차트를 구현할 기회가 있어서 Web Socket을 사용해봤다. 전에도 Gila를 구현하면서 채팅 기능을 구현했고, 해당 기능에서도 Web Socket기능을 사용했다. 하지만 제대로 이해하고 쓰는가에 대한 의문이 들어서 한번 정리해보고자 한다.

탄생 배경

우리가 사용하는 HTTP나 HTTPS와 같은 통신 규약도 충분히 데이터 전송이 가능한데 어째서 웹소켓이라는 기능이 생겼을까? 우선 HTTP의 통신 방법을 알아보면 그 이유를 알수 있다. Image 우리가 자주 사용하는 HTTP통신은 클라이언트에서 요청을 보내면 서버에서 응답을 보내주는 방식을 가지고 있다. 일반적인 상황에서는 HTTP통신 방법으로 충분히 해결이 가능하다. 하지만 우리가 사용하는 서비스의 기능을 생각해보면 이걸로 가능한가 싶은 것들이 존재한다.

스트리밍 방송의 댓글, 주식 시장, 코인 시장 등 여러개의 데이터가 계속해서 바뀌는 상황이 있다. 웹소켓이 등장하기 이전에는 이런 기능을 수행하기 위해 HTTP를 활용한 기능을 사용했다.

Polling

기존에 HTTP로 보내는 요청을 일정 시간마다 보내는 것이다.

const intervalId = setInterval(fetchSymbolList, 5000); // 5초마다 데이터 갱신

자바스크립트에서 polling을 한다면 setInterval로 일정 시간마다 동일한 요청을 보내주는 것이다. 현재 예제에서는 5초로 설정되어 있지만 더 짧은 주기로 요청을 보내면 실시간 통신처럼 보일 것이다.

하지만 이 방법의 문제는 서버 데이터에 아무런 변동이 없어도 클라이언트에서 요청을 보내고, 서버에서도 응답을 한다는 것이다. 그러다보니 서버의 부하가 증가하고 심지어 실시간 데이터라는 보장도 없다.

Long Polling

그래서 고안된 방법이 Long Pollin이라는 방식이다. 기존 polling과 서버에서 무조건적으로 데이터를 보내주는 것이 아니라 서버에 새로운 데이터가 있을때 까지 기다렸다가 응답을 보내는 것이다. 이미지설명 polling에 비해서 요청 횟수가 줄면서 서버 부하가 감소하긴 하지만 여러개의 클라이언트에서 접속한다면 서버 부하가 발생할 것이다. 그리고 이 방법또한 지연이 발생하기 때문에 실시간인지에 대한 확실함이 부족하다.

SSE

그래서 아예 서버에서 이벤트가 발생할때마다 응답을 보내는 방식이 생겼다. Server Send Event의 약자로 클라이언트에서 최초 연결한 이후에 서버에서 이벤트가 발생하면 보내주는 방식이다. 이미지설명 기존 polling이나 long polling과 다르게 실시간으로 데이터를 받을 수 있게 되었다. 하지만 이 방식은 단방향방식일 뿐이다. 클라이언트는 일방적으로 서버의 요청만 받아야하기 때문에 서버에 다른 요청을 하지 못한다.

이러한 이유로 생긴것이 Web Socket이다.

Web Socket이란?

위의 통신 프로토콜의 단점을 해결하기 위해 생긴만큼 단점을 보완하고 있다. 실시간 데이터 통신이 가능하며, 양방향 통신으로 서버로부터 데이터를 받기도 하지만 서버에 데이터를 보내는 것도 가능해진다. Image 클라이언트와 서버가 연결되어서 연결이 끊기기 전까지 데이터를 주고 받는 것이다.

Web Socket은 HTML5에서 등장했으며 TCP를 기반으로 한다.

TCP : Transmission Control Protocol의 약자로 인터넷에서 데이터를 안정적으로 전송하기 위한 프로토콜이다. 데이터를 패킷(Packet) 단위로 쪼개서 전송하고, 순서대로, 정확하게 도착하도록 보장하는 역할을 한다.

TCP는 생소한 단어이지만 HTTP나 HTTPS도 TCP위에서 동작하는 프로토콜이다. 그렇지만 Web Socekt과 HTTP가 비슷한 것은 아니다. Web Socket은 초기 연결에서만 HTTP를 사용하고, 연결된 이후에는 독립적인 프로토콜로 사용된다.

Hand Shaking

초기 연결을 하는 과정을 핸드쉐이킹(hand shaking)이라고 한다.

const socket = new WebSocket(`wss://test.com/socket`);

자바스크립트에서 웹소켓에 연결하는 코드로 생각보다 간단하게 연결이 가능하다. HTTP와 달리 wss 프로토콜로 접속하면 된다. 이렇게 요청을 보내면

GET /socket
Host: test.com
Origin: https://test.com
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Key: uzMdgc1hMJjsLUQ+OSGDYw==
Sec-WebSocket-Version: 13

위와 같은 요청 헤더를 볼수 있다. 하나씩 용도를 정리하자면

  • origin : 클라이언트에서 요청하는 origin url
  • connection - Upgrade : 클라이언트에서 프로토콜을 바꾸고 싶다는 의미
  • Upgrade - websocket : 변경을 요청한 프로토콜이 Web Socket이라는 것(https -> wss)
  • Sec-WebSocket-Key : 보안을 위해 브라우저에서 생성한 랜덤키, 해당 값을 통해 일반 http요청과 웹소켓 요청을 구분

이 요청을 서버에서 받으면 소켓 연결 수락 응답을 보내게 된다.

101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

이제 서버와 클라이언트가 연결되고 실시간으로 데이터를 주고 받을수 있게 되는 것이다. Image 핸드 쉐이킹 과정을 그림으로 나타내면 이런 모습이다.

추가적으로 웹소켓으로 주고 받는 데이터는 message라는 이름으로 온다. 그래서 브라우저에서 확인해보면 Image 메세지라는 이름의 탭에서 수신받는 데이터를 확인할 수 있다.

    socket.onmessage = (event) => {
      const data = JSON.parse(event.data);
    };

그래서 실제로 자바스크립트에서 웹소켓을 다룰때 onmessage라는 메서드를 사용해서 데이터를 받아서 사용할 수 있다.

Web socket 활용하기

이제 어떤 방식으로 서버에 요청하고 연결되는지 알았으니 간단하게 자바스크립트에서 사용하는 순서를 알아보겠다.

const socket = new WebSocket('wss://test.com');

우선 new WebSocket으로 웹소켓 연결할 url을 넣어준다. 여기에서 당연히 웹소켓 프로토콜인 wss로 요청해야한다. 핸드쉐이킹을 통해 웹소켓을 연결하게되면 웹소켓 이벤트를 사용할 수 있게 된다.

socket.open = () => { // 연결 성공했을 때
  console.log('open');
}
...
socket.onmessage = (event) => { // 데이터 수신했을 때
  const data = JSON.parse(event.data);
};
...
socket.onerror = (error) => { // 연결 에러가 발생했을 때
  console.error('WebSocket 오류:', error);
};
...
socket.close =() => { // 연결이 종료됬을 때
  console.log('close')'
};

대표적으로 4가지 이벤트를 다룬다. 자세한 사항은 Web Socket MDN을 통해 알아보면 된다.

Web Socket의 한계점

이렇게만 보면 웹소켓은 만능 기술같아 보인다. 하지만 웹 기술에서는 장점이 있다면 단점도 존재한다. 몇가지 한계를 알아보겠다.

  • 브라우저 지원 : HTML5부터 지원하는 기능으로 HTML5를 지원하지 않는 브라우저에서는 사용할 수 없음
  • 서버 부하 : 서버와 클라이언트간 지속적인 연결을 유지하기 때문에 여러개의 웹소켓 연결을 동시에 관리한다면 부하가 증가할수 있음
  • 에러처리 : HTTP의 경우 에러 코드를 통해 다양한 에러 처리가 가능하지만 웹소켓은 에러 처리에 대한 한계가 있음
  • 재연결 : 에러로 인해 연결이 끊긴다면 재연결을 직접 해줘야함.

만능같아 보이지만 부족한 부분이 있을수 밖에 없다. 각 상황에 맞춰 어떤 기술이 더 필요하고 리소스를 낭비하지 않을지 고민이 필요한 기능이다.

마무리

통신 프로토콜에 대해서 간략하게 알아봤다. 더 복잡한 내용을 담은 글도 봤지만 내가 당장 이해가 가능한 부분은 여기까지인것 같다. 그래도 알기 전보다는 많이 알게 되었으니 성장했다는 느낌은 받는다. Image 이번에 실시간 데이터를 적용해야하는 서비스를 만들어보면서 약간은 멀게 느껴졌던 웹소켓이 익숙해진 것 같다. 앞으로도 자주 볼것 같은 기술이니 더 알아가면 좋을 것 같다.

개의 댓글