HTTP 통신 기법: 폴링(Polling) 이해와 구현
HTTP는 본질적으로 비연결성(stateless, connectionless)
을 가진 프로토콜입니다.
즉, 클라이언트가 요청을 보내고 서버가 응답을 반환하면 연결은 곧바로 끊어집니다.
이 특성은 많은 웹 애플리케이션에서 문제가 되지 않지만,
실시간성이 요구되는 서비스—대표적으로 채팅 애플리케이션—에서는 곤란한 제약이 됩니다.
사용자가 메시지를 주고받을 때는 서버와 지속적으로 연결이 유지되어야 하기 때문입니다.
이번 포스트에서는 이 한계를 극복하기 위한 가장 단순한 기법인 폴링(Polling)
을 살펴보고,
직접 서버와 클라이언트 구현 예제를 만들어보겠습니다.
1. 왜 폴링이 필요한가?
실시간 통신을 하려면 서버의 데이터를 계속 확인해야 합니다.
하지만 HTTP의 비연결성 때문에 한 번의 요청으로는 지속적인 확인이 불가능합니다.
이를 극복하는 가장 단순한 방법은 주기적으로 서버에 요청을 보내는 것입니다.
마치 버스가 올 때까지 계속 정류장에서 “지금 버스 왔나요?” 하고 묻는 것과 같습니다. 버스가 오지 않았더라도 물어보는 행위는 반복됩니다.
이 단순한 방식이 바로 폴링(Polling)
입니다.
2. 폴링의 동작 원리
폴링은 다음과 같은 흐름으로 동작합니다:
- 클라이언트는 일정 주기마다 서버에 HTTP 요청을 보냅니다.
- 서버는 새로운 데이터가 있다면 응답 본문에 전달합니다.
- 데이터가 없다면 204 No Content와 같은 상태 코드를 반환합니다.
- 클라이언트는 일정 시간 대기 후 다시 요청을 반복합니다.
즉, 클라이언트는 “서버의 데이터를 당겨온다(Pull)”는 개념입니다.
3. 폴링 서버 구현하기
Node.js http
모듈을 사용해 간단한 채팅 서버를 만들어보겠습니다.
메시지 객체 정의
메시지 본문(text)
과 생성 시각(timestamp)
을 함께 저장해, 단순 문자열이 아닌 구조화된 데이터로 관리합니다.
toString()
메서드를 통해 이 객체를 JSON 문자열로 직렬화
하여 클라이언트-서버
간 전송에 활용할 수 있습니다.
class Message {
constructor(text) {
this.text = text;
this.timestamp = Date.now();
}
toString() {
return JSON.stringify({
text: this.text,
timestamp: this.timestamp,
});
}
}
js
서버 구성
HTTP 서버를 열고 /poll
로는 신규 메시지 조회, /update
로는 메시지 등록을 처리하도록 구성했습니다.
라우팅에 따라 적절한 핸들러를 실행하며, 없는 경로 요청에는 404를 반환합니다.
const http = require('http');
let message = null;
// 신규 메시지 조회
const poll = (req, res) => {
if (!message) {
res.statusCode = 204; // No Content
res.end();
return;
}
res.setHeader('Content-Type', 'application/json');
res.end(`${message}`);
message = null;
};
// 메시지 등록
const update = (req, res) => {
let body = '';
req.on('data', (chunk) => (body += chunk.toString()));
req.on('end', () => {
const { text } = JSON.parse(body);
if (!text) {
res.statusCode = 400;
res.end(JSON.stringify({ error: 'text 필드를 채워주세요' }));
return;
}
message = new Message(text);
res.end(`${message}`);
});
};
// 라우팅
const handler = (req, res) => {
const { pathname } = new URL(req.url, `http://${req.headers.host}`);
if (pathname === '/poll') return poll(req, res);
if (pathname === '/update') return update(req, res);
res.statusCode = 404;
res.end('Not Found');
};
http.createServer(handler).listen(8080, () => {
console.log('server running ::8080');
});
js
4. 요청 흐름 살펴보기
1) 메시지가 없을 때
curl http://localhost:8080/poll -v
bash
응답:
< HTTP/1.1 204 No Content
2) 메시지 등록하기
curl http://localhost:8080/update \
-H "Content-Type: application/json" \
-d '{"text":"hello"}' -v
bash
응답:
< HTTP/1.1 200 OK
{"text":"hello","timestamp":...}
3) 메시지 조회하기
curl http://localhost:8080/poll -v
bash
응답:
< HTTP/1.1 200 OK
{"text":"hello","timestamp":...}
다시 요청을 보내면 204가 반환됩니다. 이미 메시지를 소비했기 때문입니다.
5. 클라이언트 구현
브라우저에서 5초마다 /poll
요청을 보내도록 구성합니다.
const pollServer = async () => {
const INTERVAL_MS = 5_000;
const response = await fetch('/poll');
if (response.status === 204) {
setTimeout(pollServer, INTERVAL_MS);
return;
}
const message = await response.json();
render(message);
setTimeout(pollServer, INTERVAL_MS);
};
const render = (message) => {
const div = document.createElement('div');
div.textContent = `${message.text} (${new Date(
message.timestamp
).toLocaleTimeString()})`;
document.body.appendChild(div);
};
document.addEventListener('DOMContentLoaded', pollServer);
js
일단 네트워크 탭을 보면 계속 요청을 5초마다 보내고 있지만, 실제로 데이터들이 화면에 표시되어있지는 않다.
이는 우리가 당연히 서버에서 클라이언트에게 데이터를 보내지 않았기 때문이다.
curl http://localhost:8080/update \
-H "Content-Type: application/json" \
-d '{"text":"hello"}' -v
bash
이제 서버에 메시지를 업데이트하면 클라이언트 화면에 새로운 메시지가 표시됩니다.
6. 폴링의 장단점
장점
- 구현이 단순하다
- 특별한 프로토콜이나 라이브러리 없이 HTTP로 가능하다
- 빠르게 테스트하거나 프로토타입을 만들 때 유용하다
단점
- 비효율적: 데이터가 없어도 주기적으로 요청을 발생
- 네트워크 비용 증가: 불필요한 요청이 많음
- 실시간성 한계: 요청 주기에 따라 지연 발생
- 서버 부하: 클라이언트 수가 많으면 서버에 부담
7. 비유로 이해하기
폴링(Polling)
은 카톡에서 계속 “새 메시지 있어?”라고 물어보는 것과 같습니다.
메시지가 없어도 주기적으로 확인하기 때문에 데이터(요금)가 낭비되고,
서버 입장에서도 불필요한 요청이 쌓여 부담이 커집니다.
구현은 간단하지만 효율이 떨어지는 방식이므로,
보통은 푸시 알림
, WebSocket, 서버 푸시
같은 대안이 더 선호됩니다.
8. 마무리 및 다음 이야기
폴링
은 HTTP의 비연결성을 극복하기 위한 가장 단순한 기법입니다.
그러나 실시간성이 중요한 시스템에서는 효율적이지 못합니다.
그래서 다음 포스트에서는 폴링보다 진보된 방식인 롱 폴링(Long Polling)
을 살펴보겠습니다.
또한 서버 푸시(Server-Sent Events)
와 양방향 통신(WebSocket)까지 다루며, 실시간 통신 기술의 발전 과정을 정리해 보겠습니다.