🏃♂️
시리즈로 글 정리를 할 것 같은데, 총 3~4편 정도 생각하고 있습니다.
WebSocket으로 시작해서 Socket.io, Socket.io와 WebSocket의 차이, 마지막으로 Nest에서는 어떻게 WebSocket을 사용하고 있는지 이런 것들을 살펴볼 계획입니다.
주제에 대해 학습한 이유
WebSocket과 Socket.io는 다르다. 이 사실에 대해서는 어렴풋이 주워 들은 것들이 있어서 알고 있었다.
(주워 듣게 된 계기는 Postman에서 제공하는 WebSocket 테스트 기능으로 우리 서버 채팅 테스트가 안 되었던 것이다.)
이런 것들을 찾게 된 두 번째 계기는 WebSocket을 어떻게 테스트할 지 찾아본 것이었다.
부하 테스트 연습을 K6로 진행했는데, 통신 프로토콜이 HTTP와 다르니 어떻게 해야 할까 찾아가는 과정에서 자연스럽게 든 의문이었다.
그래서 WebSocket과 Socket.io의 차이점에 대해 확실히 찾아보고 학습하려고 했다.
WebSocket
정의 및 동작 원리
- 하나의 TCP 접속에서 전이중 통신 채널을 제공하는 컴퓨터 통신 프로토콜
- 전이중 통신?
- 두 지점 사이에서 정보를 주고 받는 시스템을 말한다.
- 서로 주고 받을 수 있어야 전이중 통신이다. (위키백과)
- 전이중 통신?
- WebSocket과 HTTP 모두 OSI 모델의 애플리케이션 레이어에 존재하며 4계층의 TCP에 의존한다.
WebSocket Lifecycle
- WS 핸드셰이킹 과정
- HTTP 헤더에 WS 업그레이드 헤더를 설정하고 HTTP 연결을 확인한 후 WS 프로토콜로 변경한다.
WebSocket이 연결 유지를 확인하는 방법 (참고 사이트, 참고 영상)
- 먼저 WebSocket 통신이 어떻게 이루어지는지 알아야 한다.
웹소켓은frame
이라 부르는 데이터 조각을 통해서 통신한다.
프레임은 서버와 클라이언트 모두가 서로에게 보낼 수 있고, 담긴 데이터 종류에 따라 이름이 있다.- 텍스트 프레임, 이진 데이터 프레임, 핑퐁 프레임, 커넥션 종료 프레임 등등…
- 출처: MDN
- 텍스트 프레임, 이진 데이터 프레임, 핑퐁 프레임, 커넥션 종료 프레임 등등…
⇒ 우리는 여기서 핑퐁 프레임에 주목할 필요가 있다. 커넥션이 유지되고 있는지 서버나 브라우저에서 자동 생성한 뒤 보내는 프레임이다.
김영한님이 자주 말하는 문장이 있다. ‘스프링이 용빼는 재주가 따로 있는 게 아니라~~’라는 말인데,
여기서도 적용할 수 있을 것 같다. 웹소켓이 따로 용빼는 재주가 있는 게 아니라 주기적으로 요청을 날리고 받는 걸 반복하면서 연결을 확인하는 것이다.
- 나는 여기서 새로운 의문이 들었다. 핑퐁 프레임에 의해서 클라이언트가 연결되어 있는 걸 확인했는데, 하트비트 메세지 같은 기능은 왜 구현해야 하는가?
- 프로토콜 레벨 VS 애플리케이션 레벨의 주제로 넘어올 수 있을 것 같다.
- 핑퐁은 연결 상태를 확인하지만 프로토콜 레벨에서 동작하고 오버헤드가 비교적 작다.
- 하트비트 메세지는 애플리케이션 레벨에서 개발자가 구현해야 하며, 오버헤드도 크지만 페이로드를 담을 수 있다는 장점이 있다.
⇒ 비즈니스 로직에서 상태를 체크함과 더불어 애플리케이션에 특화된 어떤 정보를 포함해야 한다면 핑퐁 프레임이 있더라도 하트비트 메세지를 구현해야 한다.
가장 쉬운 예시가 디스코드의 자리 비움 등과 같은 클라이언트 활동 상태 표시이다.
아래는 클로드를 활용해서 예시 코드를 작성한 것이다.
// Made By Claude.ai
// 클라이언트 측 예시
let lastActivity = Date.now();
// 사용자 활동 추적
document.addEventListener('mousemove', () => {
lastActivity = Date.now();
sendUserStatus('online');
});
// 주기적 상태 체크
setInterval(() => {
const inactivityTime = Date.now() - lastActivity;
if (inactivityTime > 5 * 60 * 1000) { // 5분 이상 비활성
sendUserStatus('idle');
} else {
sendUserStatus('online');
}
}, 30000);
function sendUserStatus(status) {
websocket.send(JSON.stringify({
type: 'userStatus',
status: status
}));
}
수정 1)
위의 생각과 예시에서 틀린 부분이 있는 것 같다. 브라우저에서는 핑퐁 프레임 중 pong frame만 응답
할 수 있다는 글을 보았다.
그 과정에서 하나 의문이 들었는데, 나는 핑퐁 프레임을 서버와 클라이언트가 자동으로 주고 받는 줄 알았다. 찾아보니 핑퐁 프레임이 필수가 아니며 구현해야 하는 것이라는 내용을 확인하여, 좀 더 찾은 뒤 내용을 업데이트해야 할 것 같다.
사용법(MDN)
WebSocket 객체 생성
WebSocket WebSocket(
in DOMString url,
in optional DOMString protocols
);
url
- 연결할 URL, 웹소켓 서버가 응답할 URL
protocols
프로토콜 문자열 하나 혹은 배열
서브 프로토콜을 지정하는데 사용되며, 하나의 서버가 여러 개의 웹소켓 서브 프로토콜을 구현할 수 있도록 한다.
어떻게 사용할 수 있는지, 생성형 AI를 통해 예제를 만들어봤다.
// 클라이언트 측 // 서브 프로토콜을 지정하여 WebSocket 연결 const socket = new WebSocket('ws://example.com/socket', ['chat', 'game']); // 서버 측 (Node.js with ws 라이브러리 예시) const WebSocket = require('ws'); const wss = new WebSocket.Server({ port: 8080 }); wss.on('connection', (ws, req) => { // 클라이언트가 요청한 프로토콜 확인 const protocols = req.headers\['sec-websocket-protocol'\]; // 프로토콜에 따라 다른 처리 if (protocols.includes('chat')) { ws.on('message', (message) => { // 채팅 메시지 처리 handleChatMessage(message); }); } if (protocols.includes('game')) { ws.on('message', (message) => { // 게임 관련 메시지 처리 handleGameMessage(message); }); } });
쉽게 생각하면 메시지 이벤트를 여러 카테고리로 나눠서 처리하는 것이라 이해했다. 예시처럼 chat이라는 서브 프로토콜이 지정된 경우, game으로 지정된 서브 프로토콜의 메시지는 다르게 처리할 수 있다.
// 'chat' 프로토콜의 메시지 처리 if (protocol === 'chat') { // 채팅 메시지 구조 정의 const message = { type: 'text', // or 'emoji', 'file' content: '안녕하세요', sender: 'user123', timestamp: Date.now() }; } // 'game' 프로토콜의 메시지 처리 if (protocol === 'game') { const message = { type: 'move', // or 'attack', 'chat' playerAction: 'move', coordinates: {x: 10, y: 20} }; }
참고 자료
- https://datatracker.ietf.org/doc/html/rfc6455
- https://www.peterkimzz.com/websocket-vs-socket-io
- https://ably.com/topic/socketio-vs-websocket
- https://developer.mozilla.org/ko/docs/Web/API/WebSockets_API/Writing_WebSocket_client_applications
- https://ko.wikipedia.org/wiki/%EC%9B%B9%EC%86%8C%EC%BC%93
- https://stackoverflow.com/questions/11928693/how-does-websockets-maintain-persistent-connection-and-how-stable-it-is-to-be-us
- https://www.diffusiondata.com/what-are-web-sockets-and-how-do-they-work/
- https://ko.javascript.info/websocket#ref-737
- https://brunch.co.kr/@springboot/801
- https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_servers#pings_and_pongs_the_heartbeat_of_websockets
혹시 잘못된 부분이 있다면 체크 후 코멘트 작성 부탁드립니다. 감사합니다. :)
'개발 > 개발 공부' 카테고리의 다른 글
[밑바닥부터] 3일차 - 1장 불 논리: 프로젝트 (0) | 2025.04.07 |
---|---|
[밑바닥부터] 2일차 - 1장 불 논리: 논리 게이트와 HDL 소개 (1) | 2025.04.07 |
[밑바닥부터] 1일차 - 1장 불 논리: 불 함수 개념 이해 (0) | 2025.04.04 |
밑바닥부터 만드는 컴퓨팅 시스템으로 학습하기 (0) | 2025.04.04 |
OAuth 2.0에 대해 알아보기 (0) | 2025.03.15 |