Web/TIL

HTTP와 WebSocket: 웹 페이지는 어떻게 실시간으로 변할 수 있을까?

wjdwwidz 2024. 6. 29. 22:48

 

웹 페이지는 어떻게 변하는가 ? 새로고침을 한다는 것은 새로운 요청을 보낸다는 뜻인데, 요청없이 응답이 오는 경우가 있다. 온라인 체스 게임에 임할 때, 우리는 새로고침을 하지 않아도 상대가 말을 움직이는 것을 볼 수 있다. 하지만 http 프로토콜에서는 요청이 있어야 응답을 보낼 수 있다. 전통적인 http 프로토콜에서, 클라이언트에서 응답이 없는데 서버에서 요청을 보낼 수 있을까? 그것은 불가능하다.

 

전통적인 http 통신

서버와 유저가 데이터를 주고받는 방법에는 여러가지가 있다 (ex) http 요청) 

유저가 http 요청을 날리면, 서버가 데이터를 보내주는 식으로 구현이 된다. 

 

http 요청을 쉽게 비유하자면 문자메세지와 비슷하다. 서버가 문자를 확인하면 답장으로 데이터를 보낸다. 고유한 특징이 있다면 서버가 선톡하는 경우는 없다. 항상 문자를 보내야 답변을 해줄 뿐이다.

 

예전에는 http 통신 만으로 모든 웹서비스를 다 만들 수 있었지만 게임, 채팅, 주식 거래 등 통신의 종류가 늘어나며 어려움이 증가했다. 

예를 들면, 코인 거래소에서 2초마다 서버에 있던 코인가격을 가져와 웹페이지에 띄워야 하는 상황을 생각해보자. 2초마다 서버에게 http 요청을 하면 된다. 하지만 2초마다 알아서 문자를 보내줄 수는 없는걸까? 전통적인 http 방식으로 자동 문자서비스를 구현할 수는 없다.

 

HTTP 프로토콜에서 실시간으로 소통하는 방법

http 프로토콜에서 실시간으로 소통하는 방법을 알아보자. 


1. Polling : 폴링 기법

주기적으로 요청을 보내 응답을 받는다. 일반적인 http 통신과 같이 클라이언트에서 리퀘스트를 보내고, 서버에서 응답을 보낸다. 그리고 주기적으로 n초마다 요청과 응답을 반복한다. 폴링 방법에는 어떤 단점이 있을까? 주기적으로 일어나기 때문에 실시간이 아니며, 낭비되는 요청이 생겨 서버에 부하가 생긴다.

 

2. Long Polling : 롱 폴링

이 폴링을 보안한 롱 폴링 방법이 있다. 롱 폴링은 클라이언트에서 요청을 보내고, 서버에서 응답이 올 때까지 기다린다. 서버에서 변화가 생겨서 응답을 보내면 그 즉시 클라이언트에서 요청을 보내고, 대기 하는 방법이다. 롱폴링은 기존 폴링 방법에 단점을 보완했지만, 요청과 응답이 여전히 1대1이라는 점에서 서버에 부하가 발생할 수 있다. 

 

3. Server Sent Event

"http 통신을 종료하지 않고 계속 유지"

한번 연결 후 지속적으로 응답을 받는다. 단 한번의 요청으로 연결을 지속하고, 서버측에서 변화가 생길 때마다 응답을 반복해서 보낼 수 있다.

이를 적용하면 요청이 없어도 지속적인 전송을 유지할 수 있다. 단점은 서버만 일방적으로 데이터를 보낼 수 있다.

비교하자면 라디오 같은. 유저는 지속적인 데이터 수신만 가능하고, 서버는 전송만 가능하다. 

 

 

SSE가 폴링보다 나은 점은 무엇일까? 완전히 실시간이라는 점이다. 서버에서 실시간으로 이벤트를 전송할 수 있다. 또한 polling 기법보다 적은 통신 횟수를 가지므로 비용적으로 우월하다. SSE가 웹소켓에 비해 가지는 이점은 무엇일까? 새로운 프로토콜을 익힐 필요가 없다. 러닝커브는 언제나 중요한 변수이기 때문에 이 점에서 이점이 있다. 그리고 SSE 이벤트는 서버측에서의 단방향 통신을 지원하기 때문에 양방향으로 소통을 하는 웹소켓보다 비용면에서 우월하다. 

 



이처럼 HTTP 에서도 실시간성을 보장하는 기법이 존재한다. 하지만 그럼에도 현재 웹소켓이 사용 가능 하다면 HTTP 기반의 기술들 보다 웹소켓을 이용해 실시간 서비스를 제공하는 것이 일반적이다.  왜 그런것인지, HTTP의 차이는 무엇인지 알아보자. 

 

WebSocket

실시간 통신을 얘기할 때 다양한 분들이 웹소켓을 떠올릴텐데, 웹소켓은 양방향 통신을 위해 도입된 프로토콜이고, 기존 http 프로토콜이 아닌 새로운 프로토콜이다. (ws 프로토콜 사용)

 

WebSocket은 TCP 기반이며 유저와 양방향 소통 가능하다. 비교하자면 전화. 원할 때마다 양쪽에서 누구나 말할 수 있다. 전화기를 들고있기만 해도 상대가 하는 말을 듣고, 내가 하고싶은 말을 원할 때 할 수 있는 것처럼 전화를 끊기 전까지 새로운 연결을 필요로 하지 않는다. 또한 서버든 클라이언트든 원할 때마다 메세지를 송신할 수 있다. 

 

 

WebSocket 연결 과정 

웹소켓을 연결하는 법은 간단한데, 유저가 서버에게 일단 http 요청부터 보낸다. 웹소켓으로 통신하자고 은밀하게 http 리퀘스트 부터 보내면 된다. 서버가 허락을 해주면 어느새 http 요청을 웹소켓으로 업그레이드 해줄 수 있다. WebScoket연결은 초기에 HTTP 요청을 통해 시작된다. 이 과정을 통해 WebSocket 프로토콜로의 업그레이드가 이루어진다.  

 

 

1. 초기 HTTP 요청 :

클라이언트는 서버에게 HTTP 요청을 보낸다. 이 요청은 일반적인 HTTP 요청과 유사하지만, 특별히 WebSocket 핸드셰이크를 요청하기 위해 몇 가지 추가 헤더를 포함한다.

 

예를 들어 클라이언트는 다음과 같은 HTTP요청을 보낸다. 

GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13

 

 

2. 서버의 응답 :

서버는 이 요청을 수신하고, WebSocket 핸드셰이크를 수락하면 응답을 보낸다. 이 응답에는 HTTP 상태 코드 101 Switching Protocol가 포함된다. 

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

 

 

3. WebSocket 연결 수립 : 

서버의 응답을 받은 후, 클라이언트와 서버 간의 연결이 WebSocket 프로토콜로 업그레이드 된다. 이 시점부터 서버는 지속적인 연결을 유지하며 , 양방향으로 데이터를 주고받을 수 있다. 

 

 

이후에는 연결이 WebSocket 프로토콜로 전환되어 지속적으로 데이터를 주고받을 수 있다.

 

 

 SockJS와 Socket.io

웹소켓들을 모든 환경에서 다 사용할 수 있을까? 상당히 많은 브라우저에서 지원하고 있지만, Safari의 구버전이나 FireFox 등의 환경에서는 지원하고 있지 않다. 어떤 환경에서는 실시간성을 보장하고, 어떤 환경에서는 그렇지 않다면 사용자 입장에서는 문제가 될 수 있다. 그 때 사용할 수 있는 것이 SockJS와 Socket.io이다. 이 라이브러리들을 사용하면 웹소켓을 지원하지 않는 브라우저 에서도 웹소켓을 사용하는 것과 비슷한 기능을 제공할 수 있다.

 

HTTP에서도 polling 이나 streaming 같은 기법들 처럼 웹소켓을 사용하는 것처럼 보이는 기법들이 존재하는데, SockJS와 Socket.io 이브러리들은 브라우저가 웹소켓을 지원하는지 확인해보고, 그렇지 않다면 대안책으로 그 기법들 (polling 이나 streaming ) 을 대신 사용한다. 

 

 

 

 

HTTP vs 웹소켓

HTTP 와 웹소켓의 가장 큰 차이는 수립된 커넥션을 어떻게 하느냐 이다. HTTP 의 경우 비 연결성 프로토콜. 웹소켓의 경우 한 번 요청을 보내기 전 까지 연결을 유지한다. 이렇게 얻을 수 있는 이점은 매번 요청을 맺고 끊을 때 3way, 4way 핸드쉐이크를 하는데, 웹소켓은 매번 그런 과정을 거칠 필요가 없다는 것이다. 즉 원하는 어떤 것을 얻기 위해서는 항상 그것을 달라고 요청해야 한다. 반면 웹소켓은 연결이 계속 유지되고 있는 상태이기 때문에 연결된 채널을 통해 상대가 보내오는 메세지를 듣기만 하면 된다.

 

 


참고 :