최근 웹 소켓을 이용한 프로젝트를 진행한 팀원을 보고 나도 웹 소켓을 이용한 실시간 양방향 소통 프로젝트를 하나 만들어보고자 HTTP - AJAX - Polling - Long Polling - Server-Sent Event - Web Socket 까지의 발전 과정을 통해 웹소켓을 이해한 후에 프로젝트를 진행해보고자 한다!
HTTP가 등장하기 이전 세대에서 통신한다 함은, 터미널 창에서 딱딱한 텍스트를 주고 받는 것이었다. 하지만 HTTP가 등장하니, 시각적으로나 정보량 차원에서 엄청나게 멋진 문서들을 주고 받을 수 있게 되었다.
그러나 HTTP는 사용자가 URL을 요청할 때에만! 서버에서 해당 페이지를 꺼내주는 식이라는 불편한 점이 존재한다..
HTTP를 효과적으로 이용하는 기술로써 효과적으로 서버와 소통할 수 있도록 만들어준다.
웹 서버가 요청을 받게 되면 HTML 페이지를 전송하는 것이다.
이 방식을 선택한다면, 유저는 새로운 웹페이지로 이동하는 것이 아니라, 동일한 웹페이지 내에서 DOM을 변경하게 된다!
AJAX의 등장으로 모든 페이지를 새로 받는 것이 아닌 부분적으로 변경이 가능하게 되었다!
그러나 여전히 "클라이언트의 요청이 있고 그 다음 서버로부터 응답을 받는 상황" 이 틀에서 벗어나지 못한다는 것이었다..
그러다 보니 실시간 소통을 하고 싶어도 클라이언트가 서버에게 요청하지 않는 이상 서버는 클라이언트에게 먼저 데이터를 보낼 수 없었고, 클라이언트가 항상 새로운 데이터가 있는지 확인을 하기 위해 서버에 지속적으로 요청을 보낼 수밖에 없었다.
웹 소켓이 등장 하기 전 HTTP 프로토콜을 기반으로 한 실시간 통신 방식으로 클라이언트가 주기적으로 서버에 요청을 보내는 방식이다.
일정 시간을 정해 놓고 새로운 데이터가 있는지 요청을 보내서 확인하게 되고, 새로운 데이터가 없더라도 서버는 없다고 응답을 보낸다.
// 클라이언트
setInterval(function(){
fetch('/server').then(function(response){
console.log(response);
});
}, 5000); // 5초마다 서버에 요청
// 서버 (Node.js)
app.get('/server', function(req, res){
res.send('새로운 데이터');
});
구현은 굉장히 쉽지만 불필요한 요청의 수가 굉장히 많고, 지연 시간이 발생한다..
폴링에서 조금 더 개선된 방식으로 클라이언트가 서버에 요청을 보내고 새로운 데이터가 없다면 일정 시간 동안 응답을 하지 않고 새로운 데이터가 있을 때까지 기다린다.
만약에 없다면 Time Out 응답을 보내고 있다면 즉시 응답을 해준다.
// 클라이언트
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초 후에 응답
});
폴링에 비해서 줄어든 것이지 불필요한 요청은 계속 진행된다..
지연시간도 피하지 못하고 있다
드디어 획기적인 이벤트 처리 기법이 나왔는데, 클라이언트는 최초로 한번 서버에 연결을 요청하고 이후 새로운 데이터가 생길 때마다 클라이언트에게 응답을 보내는 것이다.
즉, 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를 사용해서 실시간으로 클라이언트에게 응답을 보낼 수 있다. 하지만 이 방식은 클라이언트의 최초 요청 이후 서버만 일방적으로 응답을 하게 되는 구조다.
위의 방법들로 HTTP 통신을 활용한 실시간 통신 방식을 구현할 수는 있지만, 완벽한 실시간 통신을 보장하지는 않는다.
이 문제점을 해결하기 위해 바로 웹 소켓이 등장!
웹 소켓을 HTML5에서 실시간 웹 애플리케이션을 위해 설계된 통신 프로토콜이며, TCP를 기반으로 한다.
TCP를 기반으로 한 웹 소켓은 신뢰성 있는 데이터 전송을 보장하며, 메시지 경계를 존중하고, 순서가 보장된 양방향 통신을 제공할 수 있다.
HTTP와 다르게 클라이언트와 서버 간에 최초 연결이 이루어지면, 이 연결을 통해 양방향 통신을 지속적으로 할 수 있다.
즉, 전화 통화와 같이 양쪽 모두에서 정보를 주고 받을 수 있다는 의미
이때 데이터는 '패킷(packet)' 형태로 전달되며, 전송은 연결 중단과 추가 HTTP 요청 없이 양방향으로 이뤄진다.
패킷(packet) : 네트워크 통신에서 데이터를 작은 조각으로 나눠서 전송하는 단위
웹소켓 연결을 하려면 new WebSocket을 호출하면 되는데, 이때 ws라는 특수 프로토콜을 사용한다.
const socket = new WebSocket("ws://velog.io/@hks_0827/posts/socket");
소켓이 정상적으로 생성되면 네 개의 이벤트를 사용할 수 있게 된다.
웹 소켓은 HTTP 기반으로 초기 handshake를 수행하게 되는데, 이후 데이터 전송은 웹 소켓 프로토콜을 이용하여 통신하게 된다.
요청(Request) 헤더
GET /socket
Host: velog.io/@hks_0827/posts
Origin: https://velog.io/@hks_0827/posts
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Key: Ivyio/9s+lYongNyongczP8Q==
Sec-WebSocket-Version: 13
응답(Response) 헤더
101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: hsBYongNyong24s99EO10UlZ22C2g=
이렇게 웹 소켓 연결이 성립되면, 클라이언트와 서버 간에 실시간 양방향 통신이 가능해진다!
이제 곧 프로젝트를 진행하고자 하는데 어떻게 웹소켓이 나오게 되었고 장단점과 작동 방식을 명확히 파악할 수 있었다. 만약에 완성하면 배포까지 하고 싶은데 서버비에 대한 걱정만 커진거 같긴한데.. 서버의 자원을 적게 사용하는 법도 공부하며 프로젝트에 적용시키면 좋겠다!
[WEB] 🌐 웹 소켓 (Socket) 정리 (역사부터 차근차근)
[Web] 웹 소켓(Web Socket)이란? 등장 배경과 목적, 동작 방식 (feat. Polling, Long polling, Server-Sent Event)