그러나 웹이 발전함에 따라 통신의 '실시간성'에 대한 필요성이 높아졌다. 그런데 HTTP는 애초에 단방향성, 비연결성을 특징으로 하는 프로토콜이기 때문에 프로토콜 자체를 뜯어고치지 않는 이상 그 특징들을 바꾸는 것은 불가능했다.
이에 따라 실제로는 실시간이 아니지만 마치 '실시간인 것처럼' 느껴지도록 만드는 방법들이 고안되었는데, 그중 가장 초기의 모델이 바로 polling이라는 기법이다.
HTTP polling은 가장 단수한 방법으로 '일정 간격으로 계속해서 요청을 보내는 것'이다. 클라이언트가 서버에 일정한 간격으로 계속해서 요청을 보내면 서버는 그에 대한 응답을 하게 되므로 마치 실시간으로 통신하는 것처럼 느낄 수 있다.
HTTP polling은 다음과 같은 특징을 갖는다.
이처럼 polling은 대용량 데이터 처리 등 지금도 장점으로 여겨지는 부분이 있기는 하지만, 사실 실시간성을 확보하기에 적합한 방법은 아니다. 실시간성 확보를 위해 간격을 줄이면 서버 부하가 커지게 되는데, HTTP는 비연결성 프로토콜이기 때문에 header가 매우 무거운 프로토콜이다(클라이언트 정보, 연결에 필요한 정보 등을 헤더에 모두 담아야 하므로). 즉, 간격이 줄어들수록 서버의 부담이 막대해지는 것이다. 그렇다고 서버 부하를 줄이기 위해 시간 간격을 늘이면? 본래의 목적이었던 실시간성이 사라지게 된다.
이러한 딜레마 상태에서 새롭게 고안된 기법이 바로 long polling 기법이다.
Long polling 방식은 기본적으로 '무한하게 요청한다'는 부분에서는 polling과 동일하다. 다만 차이점이 있다면 long polling의 경우 일단 요청을 보낸 뒤 time out이 될 때까지 무한정 기다린다는 것이다.
클라이언트가 서버로 요청을 보내고, 서버가 요청을 받았을 때 만약 응답이 가능한 데이터가 없다면 그대로 대기한다. 그러다 정해진 시간이 지나 타임아웃이 발생하면 클라이언트는 바로 다시 요청을 보내 서버와 연결한다. 만약 서버가 클라이언트의 요청에 응답이 가능하다면? 서버는 응답을 보내고 연결을 종료한다. 그러나 클라이언트는 응답을 받자마자 다시 서버에 요청을 보내 연결을 지속하고 다시 대기하게 된다.
Long polling 방식은 다음과 같은 특징을 지닌다.
Streaming은 클라이언트에서 서버에 요청을 보내면, 서버가 필요한 데이터를 찾아 응답한 뒤에 연결을 끊지 않고 필요한 응답 메시지를 보내는 것을 반복하는 방식이다.
웹소켓은 HTTP 환경에서 실시간 통신이 가능하도록 하는 첨단 통신 프로토콜이다. HTTP와 달리 양방향 통신으로서 일단 연결이 이루어지면 클라이언트의 요청 없이도 서버가 데이터를 보내는 것이 가능하다. 또한 HTTP와 달리 Stateful 프로토콜로, 최초 연결 이후에는 연결이 유지되므로 TCP 커넥션에 들어가는 리소스를 아낄 수 있다는 장점이 있다.
웹소켓은 HTTP 포트 80, HTTPS 포트 443 위에서 동작한다. 즉, 새로운 방화벽을 열 필요가 없으며, HTTP 규격인 CORS 적용이나 인증 등의 과정을 기존과 동일하게 할 수 있다.
우선 TCP 연결과 마찬가지로 핸드셰이크를 이용해 최초 연결을 맺고, 이때 HTTP 업그레이드 헤더를 사용해 HTTP 프로토콜에서 웹소켓 프로토콜로 변경하는 것이다. 이렇게 연결이 맺어지면 어느 한 쪽이 연결을 끊지 않는 이상 연결이 지속되는 영구적 채널이 맺어지고, 실시간 통신이 가능해진다.
웹소켓의 핸드셰이킹 과정을 간단히 정리하면 다음과 같다.
1. 클라이언트가 서버에 연결 수립을 요청하는 HTTP 요청을 보낸다.
2. 서버는 101 코드를 보내 '프로토콜의 전환을 서버가 승인했음'을 알린다.
이 핸드셰이킹 과정에서 중요하게 보아야 할 것이 헤더 부분인데, 우선 클라이언트에서 보내는 요청의 헤더를 살펴보자.
이에 대한 응답 메시지의 헤더는 다음과 같다.
웹소켓을 통한 연결이 수립되면 데이터의 전송이 시작되며, 클라이언트와 서버는 message라는 개념으로 데이터를 주고받는다. 여기서 메시지는 '프레임'이 모여서 구성되는 논리적인 메시지 단위이며, 프레임은 작은 헤더와 페이로드로 구성된 가장 작은 단위(데이터 링크 계층에서)의 데이터를 의미한다.
웹소켓은 HTML5 이후에 나온 비교적 최신 기술이며, 따라서 HTML5 이전의 기술로 구현된 서비스에서는 웹소켓을 그대로 사용하는 것이 불가능하다. 이때 HTML5 이전에 구현된 서비스에서도 웹소켓과 유사하게 양방향 통신을 사용할 수 있도록 해 주는 것이 SockJS나 socket.io와 같은 라이브러리이다.
두 라이브러리 모두 WebSocket Emulation을 이용하는 것인데, WebSocket Emulation이란 우선 웹소켓 연결을 시도하고, 실패할 경우 HTTP-Streaming이나 Long polling 등과 같은 HTTP 기반의 다른 기술로 전환해 다시 연결을 시도하는 방법이다. node.js를 사용한다면 Socket.io를 이용하는 것이, Spring을 사용한다면 SockJS를 이용하는 것이 일반적이다.
socket.io는 표준 기술이 아닌 '라이브러리'이다. '룸'이라는 개념을 이용해 일부 클라이언트에게만 데이터를 전송하는 브로드캐스팅이 가능한 것이 특징이다.
socket.io는 양방향 통신을 위해 웹소켓 기술을 사용하는 Node.js 라이브러리와 웹소켓, 풀링, 스트리밍 등 다양한 방법을 하나의 API로 추상화한 것이다. 이를 Javascript로 구현함으로써 브라우저 종류에 상관 없이 실시간 웹을 구현하는 것이 가능하다.
socket.io와 마찬가지로 라이브러리에 해당하며. 다음과 같은 요소로 구성된다.
SockJS Client는 서버의 기본 정보를 얻기 위해 GET /info를 호출여 서버가 WebSocket을 지원하는지 여부와 전송 과정에서 쿠키 지원이 필요한지 여부, 그리고 CORS를 위한 Origin 정보 등의 정보를 응답으로 전달받는다. 이후 SockJS는 어떤 전송 타입을 사용할지를 결정한다. 이때 전송 타입은 다음의 순으로 고려된다.
1. WebSocket
2. HTTP Streaming
3. HTTP Long polling