웹 소켓 이란?

 



1.📖 들어가며

이번 포스팅은 웹 소켓(Web Scoket)에 대한 포스팅을 하려고 합니다.

 

이 글을 읽으시는 분들은 아마 웹 소켓이 무엇인지 정도는 알고 있을 것이라고 생각합니다.

 

맞습니다. 실시간 통신이 필요할 때 적극적으로 사용되는 기술입니다.

 

그럼 왜 실시간 통신을 할 때 웹 소켓을 사용하는지, 기존에는 어떤 방식을 사용했고, 어떤 문제를 해결해 주는지, 어떻게 동작하는지 등등 알아보겠습니다.

2. 웹 소켓의 등장 배경

초기의 인터넷 통신 방식은 주로 HTTP를 이용한 클라이언트(요청) - 서버(응답) 모델을 통해 진행되었습니다.

즉, 클라이언트가 서버에 요청(Request)을 보내고, 서버가 이에 응답(Response)하는 반이중 통신 방식을 따릅니다.

 

이 방식이 페이지를 요청하는 등의 간단한 작업에는 효과적입니다.

하지만, 실시간으로 데이터를 주고받는 데에 한계점이 발생하게 됩니다.

 

클라이언트가 서버에게 요청하지 않는 이상 서버는 클라이언트에게 먼저 데이터를 보낼 수 없습니다.

 

이 특징으로 실시간 데이터를 주고받는 상황을 구현하기 위해서,

클라이언트는 항상 새로운 데이터가 있는지 확인을 하기 위해 서버에 지속적으로 요청을 보낼 수밖에 없습니다.

 

이렇게 되면 트래픽을 불필요하게 증가시키고, 이로 인해 서버의 비용이 증가될 뿐더러 요청과 응답사이의 지연시간이 있기 때문에 실시간 통신의 효율성을 저하시킬 수 있습니다.

2.1. 웹 소켓 이전의 통신 방식

조금 더 자세히 알아보겠습니다.

웹 소켓이 등장 하기 전 주로 사용되던 HTTP 프로토콜을 기반으로 한 실시간 통신 방식은 어떤 것들이 있을까요?


2.1.1. 폴링(Polling)

 

Polling 동작 방식

 

클라이언트가 주기적으로 서버에 요청을 보내는 방식입니다.

즉, 일정 시간를 정해 놓고 새로운 데이터가 있는지 요청을 보내서 확인하게 됩니다.

 

이때, 새로운 데이터가 없더라도 서버는 응답을 보냅니다.

 

그래서 클라이언트는 응답을 받으면 처리하고 일정 시간 후에 다시 요청을 보내는 과정을 반복하게 되는 것이죠.

 

아래 코드 예제는 흐름의 이해를 돕기 위한 아주 간단한 예제입니다.

 
 
 
 
 
// 클라이언트
setInterval(function(){
    fetch('/server').then(function(response){
        console.log(response);
    });
}, 5000); // 5초마다 서버에 요청

// 서버 (Node.js)
app.get('/server', function(req, res){
    res.send('새로운 데이터');
});

장점으로는 매우 간단한 메커니즘이기 때문에 구현이 매우 쉽습니다.

서버 측 또한 요청에 대한 응답만 처리하면 됩니다.

 

하지만, 이 방식에는 단점이 분명히 존재합니다.

  • 불필요한 요청(Request) 수 ➡️ 서버 비용 증가
  • 요청과 응답 사이의 지연 시간이 발생합니다.

 


2.1.2. 롱 폴링(Long Polling)

 

Long Polling 동작방식

 

롱 폴링은 폴링에서 조금 더 개선된 방식입니다.

 

먼저, 동일하게 클라이언트는 서버에게 요청(Request)을 보냅니다.

이후 서버는 새로운 데이터가 없다면 일정 시간 동안 응답을 하지 않고 새로운 데이터가 있을 때까지 기다립니다.

 

만약 일정 시간 동안 새로운 데이터가 없다면 Time Out이 발생하고, 이때 서버는 Time Out에 대한 응답을 보냅니다..

반면에 새로운 데이터가 있다면 즉시 새로운 데이터에 대한 응답(Resonse)을 보냅니다.

 

아래 코드도 마찬가지로, 흐름에 대한 이해를 돕기 위한 간단한 예제입니다.

 
 
// 클라이언트
function longPoll(){
    fetch('/server').then(function(response){
        console.log(response);
        longPoll();
    });
}
longPoll();

// 서버 (Node.js)
app.get('/server', function(req, res){
    setTimeout(function(){
        res.send('새로운 데이터');
    }, 10000); // 10초 후에 응답
});

 

폴링과 아주 유사합니다.

유사하지만 폴링에 비해서 불필요한 요청(Request) 수는 줄어들게 됩니다.

 

폴링에 비해서 줄어든 것이지 불필요한 요청은 계속 진행됩니다.

또한, 요청과 응답 사이에 발생하는 지연 시간은 불가피할 수 있습니다.


2.1.3. 서버 센트 이벤트(Server-Sent Event)

 

Server-Sent Event 동작방식

 

서버 센트 이벤트 방식은 위 방식들과는 조금 다르게 동작합니다.

 

클라이언트는 최초로 한 번 서버에 연결을 요청합니다.

그럼 서버는 요청을 받고, 이후 새로운 데이터가 생길 때마다 적절히 처리하여 클라이언트에게 응답을 보냅니다.

 

즉, HTTP 통신을 종료하지 않고 연결을 유지하는 방식입니다.

 

아래 코드도 마찬가지로, 흐름에 대한 이해를 돕기 위한 간단한 예제입니다.

 
// 클라이언트
const source = new EventSource("/server");
source.onmessage = function(event) {
    console.log(event.data);
};

// 서버 (Node.js)
app.get('/server', function(req, res){
    res.setHeader('Content-Type', 'text/event-stream');
    setInterval(function(){
        res.write('data: 새로운 데이터\n\n');
    }, 5000); // 5초마다 데이터 전송
});

SSE를 사용하여 실시간으로 클라이언트에게 응답을 보낼 수 있습니다.

또한, 이벤트 기반으로 서버에서 보낸 메시지에 대해 이벤트 처리가 가능합니다.

연결이 끊어진 경우에도 SSE는 자동으로 재연결을 시도합니다.

 

하지만 이 방식은 클라이언트의 최초 요청 이후 서버만 일방적으로 응답을 하게 됩니다.

즉, 우리가 청취하는 라디오와 같다고 볼 수 있습니다.

 

위에서 알아본 방식들로 HTTP 통신으로 실시간 통신 방식을 구현할 수 있습니다.

하지만, 단지 실시간 통신을 구현하기 위한 방법일 뿐, 완벽한 실시간 통신을 보장하지는 않습니다.

 

그래서 이 문제점을 해결하기 위해 바로 웹 소켓(Web Socket)이 등장했습니다.


2.2. 웹 소켓(Web Socket)이란?

 

Web Socket 동작 방식

 

웹 소켓은 HTML5에 등장 실시간 웹 애플리케이션을 위해 설계된 통신 프로토콜이며, TCP(Transmission Control Protocol)를 기반으로 합니다.

TCP를 기반으로 한 웹 소켓은 신뢰성 있는 데이터 전송을 보장하며, 메시지 경계를 존중하고, 순서가 보장된 양방향 통신을 제공할 수 있습니다.

 

HTTP와 다르게 클라이언트와 서버 간에 최초 연결이 이루어지면, 이 연결을 통해 양방향 통신을 지속적으로 할 수 있습니다.

즉, 전화 통화와 같이 양쪽 모두에서 정보를 주고받을 수 있다는 의미입니다.

 

'지속적 연결'을 통해서 서버는 클라이언트에게 실시간으로 데이터를 보낼 수 있으며, 반대로 클라이언트도 서버에게 데이터를 보낼 수 있습니다.


이때 데이터는 ‘패킷(packet)’
형태로 전달되며, 전송은 연결 중단과 추가 HTTP 요청 없이 양방향으로 이뤄집니다.

패킷(packet)이란❓
네트워크 통신에서 데이터를 작은 조각으로 나눠서 전송하는 단위를 말합니다.

 

웹소켓 연결을 하려면 new WebSocket을 호출하면 되는데, 이때 ws라는 특수 프로토콜을 사용합니다.

const socket = new WebSocket("ws://yong-nyong.tistory.com/socket");

ws 말고 wss://라는 프로토콜도 존재하며, 두 프로토콜의 관계는 HTTP와 HTTPS의 관계와 유사합니다.

 

소켓이 정상적으로 생성되면 아래 네 개의 이벤트를 사용할 수 있게 됩니다.

  • open – 연결이 성공적으로 되었을 때 발생
  • message – 데이터를 수신하였을 때 발생
  • error – 연결 상 에러가 생겼을 때 발생
  • close – 연결이 종료되었을 때 발생

추가 속성은 공식 문서 에서 확인해 주세요.


2.2.1. 웹 소켓 핸드셰이크(handshake)

new WebSocket(url)을 호출해 소켓을 생성하면 즉시 연결이 시작됩니다.

 

웹 소켓은 HTTP 기반으로 초기 handshake를 수행합니다.
이후, 데이터 전송은 웹 소켓 프로토콜을 이용하여 통신하게 됩니다.

 

new WebSocket("wss://yong-nyong-tistory.com/socket")을 호출해 최초 요청을 전송했다고 가정합시다.

 

이때의 요청(Reqeust) 헤더를 살펴보면 아래와 같습니다.

 
 
GET /socket
Host: yong-nyong-tistory.com
Origin: https://yong-nyong-tistory.com
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Key: Ivyio/9s+lYongNyongczP8Q==
Sec-WebSocket-Version: 13
  • Origin – 클라이언트 origin을 나타냅니다.
  • Connection: Upgrade – 클라이언트 측에서 프로토콜을 바꾸고 싶다는 신호를 보냈다는 것을 나타냅니다. (https ➡️ wss)
  • Upgrade: websocket – 클라이언트 측에서 요청한 프로토콜은 'websocket’이라는 것을 의미합니다. (https ➡️ wss)
  • Sec-WebSocket-Key – 보안을 위해 브라우저에서 생성한 키로, 서버가 웹소켓 프로토콜을 지원하는지를 확인하는 데 사용됩니다.
  • Sec-WebSocket-Version – 웹소켓 프로토콜 버전을 나타냅니다.

 

다음으로 서버가 해당 요청을 받으면 웹 소켓 연결을 수락하는 응답을 보냅니다.

해당 응답에는 '101 Switching Protocols' 상태 코드와 함께 응답합니다.

 
101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: hsBYongNyong24s99EO10UlZ22C2g=

 

이 과정을 통해서 클라이언트와 서버 간 실시간 통신이 가능한 통로가 열리게 되는 것입니다.

 

이렇게 웹 소켓 연결이 성립되면, 클라이언트와 서버 간에 실시간 양방향 통신이 가능해집니다.


데이터 전송은 '프레임(Frame)'이라는 단위로 전송됩니다.
각 프레임은 텍스트 데이터 또는 이진 데이터를 포함할 수 있습니다.

✔️ 텍스트 프레임(text frame): 텍스트 데이터가 담긴 프레임
✔️  이진 데이터 프레임(binary data frame): 이진 데이터가 담긴 프레임
✔️  핑·퐁 프레임(ping/pong frame): 커넥션이 유지되고 있는지 확인할 때 사용하는 프레임으로 서버나 브라우저에서 자동 생성해서 보내는 프레임
✔️ 이 외에도 커넥션 종료 프레임(connection close frame) 등 다양한 프레임이 존재합니다.

 


2.3. 웹 소켓(Web Socket)의 한계점

모든지 장점이 있으면 단점이 있기 마련입니다. 

그렇다면 단점은 무엇이 있을까요?

  • 브라우저 지원: 웹 소켓은 HTML5 사양의 일부입니다. 즉, HTML5를 지원하지 않는 브라우저에서는 사용할 수 없습니다.
  • 서버 비용: 웹 소켓은 지속적인 연결을 유지하므로, 많은 수의 웹소켓 연결을 동시에 관리해야 하는 경우 서버의 부하가 증가할 수 있습니다.
  • 다양한 에러처리: 만약 연결이 끊어졌을 시 어떤 이유에서 연결이 끊어졌는지와 같은 상세한 에러 처리에 대한 한계가 있습니다. 웹소켓은 연결이 끊어진 이유에 대해서 정확히 알 수 없습니다.
  • 재연결 처리: 알 수 없는 에러로 인해 연결이 끊어지면 지속적인 연결을 해야 하는 웹 소켓 특성상 재연결을 할 수 있도록 구현해야 합니다. 웹소켓은 자동으로 재연결을 진행하지 않습니다.

3. 📕 마무리

이로서, 실시간 양방향 통신을 쉽게 구현할 수 있도록 해주는 웹 소켓(Web Socket)에 대한 정의, 등장 배경, 동작방식, 한계점에 대해서 알아봤습니다.

 

최근 빠른 주기로 갱신이 발생하는 실시간 데이터를 처리함에 있어서 웹 소켓을 사용했습니다.

웹 소켓의 역할만 알고 있었던 상황인지라, 근본적으로 깊게 알아볼 필요가 있다고 생각하여 이렇게 포스팅하게 되었습니다.

 

웹 소켓을 지원하는 라이브러리도 몇 가지 있으며, 웹 소켓의 한계점을 어느 정도 해결하고 사용을 간편하게 해 줍니다.

 

하지만 한계점을 해결해 준다고 해서 무조건 좋은 것만은 아닙니다.

 

일반 웹 소켓은 라이브러리보다 가볍고 빠르며, 더 적은 서버 자원을 사용합니다.

또한, 재연결 로직 같은 기능도 직접 구현할 수 있습니다.

따라서 상황에 따라 일반 웹 소켓과 라이브러리 중 더 나은 선택을 하는 것을 추천합니다.