WebSocket은 TCP 소켓 연결을 통해 클라이언트와 서버 간의 양방향 통신을 가능하게 합니다. 일반적인 HTTP 통신에서는 클라이언트가 요청을 보내고 서버가 응답을 반환하는 방식으로 동작합니다. 반면 WebSocket은 클라이언트가 연결을 초기화한 후 지속적으로 열린 연결을 유지하며 양측이 데이터를 자유롭게 보낼 수 있습니다.
최신 브라우저는 대부분 웹 소켓을 지원하며, 노드는 ws나 Socket.IO 같은 패키지를 통해 웹 소켓 사용 가능합니다.

WebSocket 통신은 처음에 HTTP 요청을 통해 시작됩니다. 이 과정은 "핸드셰이크"라고 불립니다. 클라이언트는 서버에 WebSocket 연결을 요청하는데, 이 과정은 다음과 같습니다.
클라이언트의 업그레이드 요청
Upgrade 헤더가 포함된 특별한 HTTP GET 요청을 보냅니다.Connection: Upgrade, Upgrade: websocket 등이 명시됩니다.GET /chat HTTP/1.1
Host: example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13
서버의 응답
101 Switching Protocols라는 상태 코드와 함께 WebSocket 연결을 승인합니다.Sec-WebSocket-Key를 기반으로 새로운 값을 계산해 Sec-WebSocket-Accept 헤더로 반환합니다. 이를 통해 클라이언트는 서버의 응답이 유효한지 확인할 수 있습니다.HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
핸드셰이크가 완료되면 WebSocket 연결이 확립되며, 이 시점부터는 클라이언트와 서버가 기존의 HTTP 요청/응답 사이클을 벗어나 양방향으로 데이터를 주고받을 수 있게 됩니다.
지속적인 연결
프레임 기반 통신
양방향 통신
WebSocket은 두 가지 주요 데이터 유형인 텍스트 메시지와 바이너리 메시지를 지원합니다. 데이터는 프레임이라는 작은 조각으로 나뉘어 전송되며, 다음과 같은 구조로 전송됩니다.
WebSocket 연결은 클라이언트나 서버가 언제든지 종료할 수 있습니다. 종료 과정은 다음과 같습니다.

HTTP
💡 Polling
웹소켓 등장 이전에 웹 애플리케이션에서 서버와 실시간으로 데이터를 주고받기 위해 주로 사용하던 방식 중 하나로 HTTP의 가장 큰 특징이자 단점이 될 수 있는 단방향 통신을 해결하기 위해 HTTP 프로토콜을 활용해 억지로 양방향 통신을 구현한 것입니다. 이 방식은 클라이언트(브라우저)가 일정한 시간 간격으로 서버에 데이터를 요청하여 서버의 상태나 업데이트된 정보를 확인하는 방식입니다.
WebSocket
HTTP
WebSocket
HTTP
WebSocket
HTTP
WebSocket
HTTP
WebSocket
| 특성 | HTTP | WebSocket |
|---|---|---|
| 통신 방식 | 요청-응답 | 양방향 통신 |
| 연결 유지 | 비연결형, 요청 시마다 새 연결 | 지속적 연결 |
| 통신 방향 | 단방향 (클라이언트 → 서버) | 양방향 (클라이언트 ↔ 서버) |
| 실시간성 | 폴링이나 롱 폴링으로 실시간 구현 가능 | 실시간 통신에 매우 적합 |
| 오버헤드 | 각 요청에 헤더 포함 | 핸드셰이크 이후 헤더 오버헤드 없음 |
| 활용 사례 | 정적 콘텐츠 제공, 요청 기반 데이터 | 실시간 채팅, 알림, 게임, IoT 등 |
WebSocket은 HTTP의 단방향성 한계를 극복하고, 실시간으로 양방향 소통이 필요한 상황에서 뛰어난 효율성과 성능을 제공합니다. 반면 HTTP는 간단한 요청-응답이 필요한 웹 콘텐츠 제공에 더 적합한 프로토콜입니다.
ws는 Node.js에서 순수한 WebSocket 프로토콜을 구현하기 위한 가장 기본적인 라이브러리입니다. 매우 경량이며, WebSocket 표준을 직접 사용합니다. 불필요한 부가 기능 없이 간단한 실시간 통신을 구현하고자 할 때 적합합니다.
WebSocket.Server의 메서드와 이벤트
주요 객체
WebSocket.Server): 서버를 생성하기 위한 객체입니다. 클라이언트와의 연결을 관리하며, 여러 이벤트 리스너를 설정하여 클라이언트와의 소통을 지원합니다.WebSocket): 서버 또는 클라이언트 측에서 WebSocket 연결을 나타내는 객체입니다. 각 클라이언트와의 연결을 이 객체를 통해 처리합니다.WebSocket.Server의 메서드와 이벤트
new WebSocket.Server(options): WebSocket 서버를 생성하는 생성자입니다. 여기서 options 객체를 통해 포트 번호와 같은 설정을 할 수 있습니다.const server = new WebSocket.Server({ port: 8080 });server.on(event, callback): 특정 이벤트가 발생했을 때 실행할 콜백 함수를 설정합니다.event는 아래와 같이 구성됩니다:
connection: 클라이언트가 연결될 때 발생합니다. 콜백 함수는 연결된 WebSocket 객체를 인자로 받습니다.
server.on('connection', (socket) => {
console.log('새 클라이언트가 연결되었습니다.);
});
close: 서버가 종료되거나 연결이 종료될 때 발생합니다.
server.on('close', () => {
console.log('서버가 종료되었습니다.');
});
error: 서버에서 오류가 발생했을 때 호출됩니다.
server.on('error', (error) => {
console.log(`에러가 발생했습니다: ${error.message}`);
});
socket.send(data): 서버 또는 클라이언트가 상대방에게 데이터를 전송합니다. data는 문자열 또는 바이너리 형식일 수 있습니다.socket.send('안녕하세요, 클라이언트!');socket.on(event, callback): 특정 이벤트에 대해 콜백을 설정합니다.event는 아래와 같이 구성됩니다:
message: 상대방으로부터 메시지를 받을 때 발생합니다. 콜백 함수는 수신된 메시지를 인자로 받습니다.
socket.on('message', (message) => {
console.log(`받은 메시지: ${message}`);
});
close: 연결이 닫힐 때 발생합니다.
socket.on('close', () => {
console.log('연결이 닫혔습니다.');
});
error: 연결 중 오류가 발생할 때 호출됩니다.
socket.on('error', (error) => {
console.log(`에러가 발생했습니다: ${error.message}`);
});
socket.close(): WebSocket 연결을 닫습니다. 연결이 닫히면 close 이벤트가 발생합니다.WebSocket 객체는 addEventListener 메서드를 통해 다양한 이벤트에 리스너를 추가할 수 있습니다. 이 방식은 이벤트 리스너를 설정하는 또 다른 방법으로, 이벤트 기반 통신에서 자주 사용됩니다. onmessage, onopen, onclose 등 속성을 설정하는 방법과 비슷하지만, 이 방식은 이벤트 리스너를 여러 개 추가할 수 있다는 장점이 있습니다.
주요 이벤트
open: WebSocket 연결이 성공적으로 열렸을 때 발생하는 이벤트입니다.message: 서버로부터 메시지가 도착했을 때 발생하는 이벤트입니다.close: WebSocket 연결이 닫혔을 때 발생하는 이벤트입니다.error: WebSocket 연결에서 오류가 발생했을 때 발생하는 이벤트입니다.// WebSocket 서버에 연결
const socket = new WebSocket('ws://localhost:3000');
// 'open' 이벤트 리스너 추가
socket.addEventListener('open', (event) => {
console.log('WebSocket 연결이 열렸습니다.');
socket.send('서버에 메시지를 전송합니다.');
});
// 'message' 이벤트 리스너 추가
socket.addEventListener('message', (event) => {
console.log(`서버로부터 받은 메시지: ${event.data}`);
});
// 'close' 이벤트 리스너 추가
socket.addEventListener('close', (event) => {
console.log('WebSocket 연결이 종료되었습니다.');
});
// 'error' 이벤트 리스너 추가
socket.addEventListener('error', (event) => {
console.error('WebSocket 오류 발생:', event);
});
ws 모듈을 사용하여 간단한 채팅을 구현한 예시입니다.
서버에 ws 모듈 설치하기
npm install ws
서버 코드
// backend/server.js
const WebSocket = require("ws");
// 포트 3000번에서 WebSocket 서버를 실행
const server = new WebSocket.Server({ port: 3000 });
// backend/server.js
server.on("connection", (ws) => {
console.log("클라이언트가 연결되었습니다.");
// 클라이언트로부터 메시지를 받았을 때
ws.on("message", (message) => {
console.log(`클라이언트로부터 받은 메시지: ${message}`);
// 연결된 모든 클라이언트에게 메시지를 브로드캐스트
server.clients.forEach((client) => {
if (client.readyState === WebSocket.OPEN) {
client.send(message.toString()); // 메시지를 문자열로 전송
}
});
});
// 연결이 종료되었을 때
ws.on("close", () => {
console.log("클라이언트가 연결을 종료했습니다.");
});
// 클라이언트에게 초기 메시지 전송
ws.send("웹소켓 서버에 연결되었습니다.");
});
클라이언트 코드
<!-- frontend/index.html -->
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>Socket.IO</title>
</head>
<body>
<h1>Socket.IO</h1>
<div id="chat">
<div id="messages"></div>
<input id="messageInput" type="text" placeholder="메시지를 입력하세요" />
<button id="sendButton">전송</button>
</div>
<script>
// 서버와 연결
const socket = io('http://localhost:3000');
socket.on('connect', () => {
console.log('서버에 연결되었습니다.');
});
// 메시지 전송 버튼 클릭 시 메시지를 서버로 보냄
document.getElementById('sendButton').addEventListener('click', () => {
const messageInput = document.getElementById('messageInput');
const message = messageInput.value;
if (message.trim() !== '') {
socket.emit('chat message', message); // 서버로 메시지 전송
messageInput.value = ''; // 메시지 입력 필드 초기화
}
});
// 서버로부터 받은 메시지를 화면에 표시
socket.on('chat message', (message) => {
const messagesDiv = document.getElementById('messages');
const messageElement = document.createElement('div');
messageElement.textContent = message;
messagesDiv.appendChild(messageElement);
});
socket.on('disconnect', () => {
console.log('서버와의 연결이 종료되었습니다.');
});
</script>
</body>
</html>
Web Socket은 HTML5의 기술이기 때문에오래된 버전의 웹 브라우저는 Web Socket을 지원하지 않습니다. 특히 자동 업데이트가 되지 않는 익스플로러 구 버전 사용자들은 Web Socket으로 작성된 웹페이지를 볼 수 없습니다. 따라서 이를 해결하기 위해 나온 여러 기술 중 하나가 Socket.io 입니다.웹페이지가 열리는 브라우저가 웹소켓을 지원하면 웹소켓 방식으로 동작하고,지원하지 않는 브라우저라면 일반 http를 이용해서 실시간 통신을 흉내내는 것입니다.
Socket.io는 자바스크립트를 이용하여 브라우저 종류에 상관없이 실시간 웹을 구현할 수 있도록 한 기술입니다. WebSocket뿐만 아니라 폴백 메커니즘을 사용하여 다양한 실시간 통신 방식(예: HTTP 폴링)을 지원합니다. WebSocket 프로토콜을 이용하지만, 추가적인 기능(브로드캐스팅, 룸, 자동 재연결 등)을 제공하여 실시간 통신을 구현하는 데 더 유연한 환경을 제공합니다.
주요 객체
Server (io): Socket.IO 서버 객체로, 여러 클라이언트와의 연결을 관리합니다.Socket (socket): 개별 클라이언트와의 연결을 나타내는 객체로, 클라이언트와 서버 간의 통신을 담당합니다.Server 객체의 메서드와 이벤트
require('socket.io')(port, options): 서버를 생성하며, 주어진 포트에서 실행합니다.const io = require('socket.io')(3000);io.on(event, callback) : 이벤트 리스너를 설정합니다.connection: 새로운 클라이언트가 연결되었을 때 호출됩니다. 콜백 함수는 연결된 클라이언트의 socket 객체를 인자로 받습니다.
io.on('connection', (socket) => {
console.log('새 클라이언트가 연결되었습니다.');
});
io.emit(event, data): 연결된 모든 클라이언트에게 이벤트와 데이터를 전송합니다.io.emit('broadcast', '모든 클라이언트에게 메시지를 보냅니다.');Socket 객체의 메서드와 이벤트
socket.on(event, callback): 특정 이벤트에 대해 콜백을 설정합니다.message: 기본 이벤트로, 클라이언트가 서버에 데이터를 전송할 때 호출됩니다.socket.on('message', (data) => {
console.log(`클라이언트로부터 받은 메시지: ${data}`);
});socket.on('chat message', (msg) => {
console.log(`받은 채팅 메시지: ${msg}`);
});socket.emit(event, data): 현재 연결된 클라이언트에게 이벤트와 데이터를 전송합니다.socket.emit('response', '서버로부터 응답 메시지');socket.broadcast.emit(event, data): 현재 연결된 클라이언트를 제외한 나머지 모든 클라이언트에게 이벤트와 데이터를 전송합니다.socket.broadcast.emit('new user', '새 사용자가 접속하였습니다.');io.of(namespace)): 네임스페이스는 서로 다른 목적의 통신 채널을 분리하기 위해 사용합니다.const chat = io.of('/chat');
chat.on('connection', (socket) => {
console.log('채팅 네임스페이스에 연결되었습니다.');
});socket.join(room)과 같은 메서드를 사용하여 여러 클라이언트를 그룹화합니다.socket.join('room1');
io.to('room1').emit('message', '룸1에 있는 모든 사용자에게 메시지 전송');Socket.IO 모듈을 사용하여 간단한 채팅을 구현한 예시입니다.
Socket.IO는 서버와 클라이언트 모두 설치가 필요합니다.
npm install socket.io socket.io-client
서버 코드
// backend/server.js
const io = require('socket.io')(3000, {
cors: {
origin: "*", // 모든 도메인에서 접근 허용 (개발용으로만 사용)
methods: ["GET", "POST"]
}
});
io.on('connection', (socket) => {
console.log('클라이언트가 연결되었습니다.');
// 클라이언트로부터 채팅 메시지를 받았을 때
socket.on('chat message', (message) => {
console.log(`클라이언트로부터 받은 메시지: ${message}`);
// 연결된 모든 클라이언트에게 메시지를 브로드캐스트
io.emit('chat message', message);
});
// 연결이 종료될 때
socket.on('disconnect', () => {
console.log('클라이언트가 연결을 종료했습니다.');
});
});
클라이언트 코드
<!-- frontend/index.html -->
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>Socket.IO</title>
<script src="https://cdn.socket.io/4.0.0/socket.io.min.js"></script>
</head>
<body>
<h1>Socket.IO</h1>
<div id="chat">
<div id="messages"></div>
<input id="messageInput" type="text" placeholder="메시지를 입력하세요" />
<button id="sendButton">전송</button>
</div>
<script>
// 서버와 연결
const socket = io('http://localhost:3000');
socket.on('connect', () => {
console.log('서버에 연결되었습니다.');
});
// 메시지 전송 버튼 클릭 시 메시지를 서버로 보냄
document.getElementById('sendButton').addEventListener('click', () => {
const messageInput = document.getElementById('messageInput');
const message = messageInput.value;
if (message.trim() !== '') {
socket.emit('chat message', message); // 서버로 메시지 전송
messageInput.value = ''; // 메시지 입력 필드 초기화
}
});
// 서버로부터 받은 메시지를 화면에 표시
socket.on('chat message', (message) => {
const messagesDiv = document.getElementById('messages');
const messageElement = document.createElement('div');
messageElement.textContent = message;
messagesDiv.appendChild(messageElement);
});
socket.on('disconnect', () => {
console.log('서버와의 연결이 종료되었습니다.');
});
</script>
</body>
</html>
ws와 Socket.IO는 모두 Node.js에서 WebSocket 프로토콜을 사용하여 클라이언트와 서버 간의 실시간 통신을 구현하는 라이브러리입니다. 그러나 이 둘은 기능적, 구조적, 사용 편의성 측면에서 차이가 있습니다.
ws
ws는 순수한 WebSocket 프로토콜만을 구현하는 경량 라이브러리입니다. WebSocket 프로토콜만을 사용하기 때문에 직접 WebSocket 연결을 관리해야 합니다.Socket.IO
Socket.IO는 WebSocket을 포함한 다양한 실시간 통신 방법을 자동으로 지원합니다. WebSocket을 기본으로 사용하지만, 클라이언트가 WebSocket을 지원하지 않는 경우 자동으로 HTTP 폴링 등의 방법으로 폴백(fallback)할 수 있습니다.ws
ws는 순수한 WebSocket 연결만을 제공하기 때문에 매우 경량이고, 최소한의 기능만 포함되어 있습니다.Socket.IO
Socket.IO는 다양한 부가 기능을 제공합니다Socket.IO는 채팅 애플리케이션이나 게임과 같은 복잡한 실시간 애플리케이션을 구현할 때 매우 유용합니다.ws
ws는 WebSocket 표준에 매우 충실하여 간단하고 경량입니다. 따라서 설정과 사용이 비교적 간단하며, 초기에 WebSocket 프로토콜을 잘 이해하고 있는 개발자라면 사용하기 수월합니다.Socket.IO
Socket.IO는 설정이 다소 복잡할 수 있지만, 다양한 기능을 손쉽게 활용할 수 있는 장점이 있습니다. 예를 들어, 서버에서 여러 클라이언트를 연결하고 특정 그룹에만 메시지를 보낼 때 별도의 복잡한 설정 없이도 룸 기능을 사용하면 쉽게 구현할 수 있습니다.ws
Socket.IO
ws
ws는 WebSocket 표준에 따른 프레임 단위의 전송을 사용하며, 데이터 오버헤드가 거의 없습니다. 매우 경량화된 프레임을 사용해 네트워크 부하를 줄일 수 있습니다.Socket.IO
Socket.IO는 다양한 기능을 제공하는 만큼, 각 데이터 전송에 추가적인 프로토콜 오버헤드가 발생합니다. 이벤트의 이름이나 데이터 구조 관리 등의 부가적인 데이터를 포함해 전송하기 때문에 기본 ws 라이브러리에 비해 오버헤드가 큽니다.| 특성 | ws | Socket.IO |
|---|---|---|
| 프로토콜 | WebSocket만 지원 | WebSocket + 폴백 메커니즘 (HTTP 폴링 등) |
| 기능 | 기본적인 WebSocket 기능 제공 | 이벤트 기반 통신, 자동 재연결, 룸, 네임스페이스 등 |
| 설정 편의성 | 간단하고 경량 | 설정이 다소 복잡하나 다양한 기능 지원 |
| 호환성 | 브라우저에서 WebSocket만 사용 가능 | 폴백 기능을 통해 호환성 높음 |
| 오버헤드 | 최소한의 데이터 오버헤드 | 부가적인 데이터 오버헤드 발생 |
| 사용 예시 | 간단한 실시간 데이터 전송 | 채팅, 게임 등 복잡한 실시간 애플리케이션 |
ws는 단순하고 가벼운 실시간 애플리케이션에 적합하고, Socket.IO는 더 복잡한 기능을 손쉽게 구현할 수 있어 다양한 요구사항을 가진 실시간 시스템에서 유리합니다.