-
Notifications
You must be signed in to change notification settings - Fork 3
WebSocket과 Socket.io에 대해 간단히 알아보기
- 웹소켓(WebSocket)은 웹 브라우저와 서버 간 양방향 통신을 위한 프로토콜
- 클라이언트가 서버에 처음 연결을 시도할 때는 HTTP 프로토콜을 사용하지만, 연결이 완료되면 HTTP가 아닌 독립적인 프로토콜인 웹소켓을 통해 통신
- 즉, HTTP ≠ WebSocket. 둘은 TCP 소켓으로 구현되는 독립적인 프로토콜임
- 웹소켓은 실시간으로 데이터를 주고받아야 하는 애플리케이션(예: 채팅, 게임, 금융 트레이딩 시스템 등)에 적합
- 웹소켓의 가장 큰 장점은 서버가 클라이언트에게 실시간으로 데이터를 푸시할 수 있다는 점. 오버헤드를 줄여 효율적인 실시간 통신을 가능하게 함.
- RFC 6455는 웹소켓 프로토콜의 표준 규격을 정의한 문서로, 웹소켓이 초기 핸드셰이크(Handshake) 과정과 메시지 프레임 구조를 설명
-
핸드셰이크(Handshake):
-
웹소켓은 HTTP 프로토콜을 사용하여 연결을 시작. 이 과정에서 클라이언트는 서버에
Upgrade
헤더를 포함하여 웹소켓으로 프로토콜을 업그레이드하도록 요청. -
클라이언트의 요청에 응답하여 서버가
101 Switching Protocols
상태 코드를 반환하면, HTTP 연결은 웹소켓 연결로 전환. -
클라이언트 요청 예시
GET /chat HTTP/1.1 Host: server.example.com Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== Sec-WebSocket-Version: 13
-
Sec-WebSocket-Key
는 클라이언트가 서버로 전달하는 랜덤 키로, 서버는 이 키를 바탕으로Sec-WebSocket-Accept
응답을 생성하여 보안을 확보함.
-
-
서버 응답 예시
HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
-
-
프레임 기반 통신:
- 핸드셰이크가 완료되면, 클라이언트와 서버는 프레임(frame) 단위로 데이터를 주고받음.
- 프레임 구조에는 메시지의 시작과 끝을 표시하는 비트, 데이터 유형, 마스킹, 그리고 페이로드 데이터(전송할 데이터)가 포함
- 프레임 구조
-
FIN
: 메시지 종료 여부를 나타내는 비트 -
Opcode
: 메시지의 유형. 텍스트(1), 바이너리(2), 핑(9), 퐁(10) 등이 있음. -
Masking Key
: 보안상 이유로, 클라이언트에서 서버로 보내는 데이터는 반드시 마스킹이 적용됨. -
Payload Data
: 실제 전송할 메시지의 데이터
-
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-------+-+-------------+-------------------------------+
|F|R|R|R| opcode|M| Payload len | Extended payload length |
|I|S|S|S| (4) |A| (7) | (16/64) |
|N|V|V|V| |S| | (if payload len==126/127) |
| |1|2|3| |K| | |
+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
| Extended payload length continued, if payload len == 127 |
+ - - - - - - - - - - - - - - - +-------------------------------+
| | Masking-key, if MASK set to 1 |
+-------------------------------+-------------------------------+
| Masking-key (continued) | Payload Data |
+-------------------------------- - - - - - - - - - - - - - - - +
: Payload Data continued ... :
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| Payload Data continued ... |
+---------------------------------------------------------------+
- FIN (1 bit): 마지막 프레임 여부
- RSV1-3 (3 bits): 예약된 비트, 일반적으로 0
- Opcode (4 bits): 프레임 타입 (0x1: 텍스트, 0x2: 바이너리, 0x8: 연결 종료 등)
- MASK (1 bit): 페이로드 마스킹 여부
- Payload length (7 bits + 16/64 bits): 페이로드 길이
- Masking-key (32 bits): 마스킹에 사용되는 키
- Payload: 실제 데이터
특징 | HTTP | WebSocket |
---|---|---|
통신 방식 | 클라이언트가 요청하면 서버가 응답 | 양방향 통신, 서버에서 클라이언트로 푸시 가능 |
연결 지속성 | 요청마다 새로운 연결을 수립 | 초기 연결 후 지속적 연결 유지 |
오버헤드 | 요청마다 헤더 포함 | 초기 연결 이후에는 헤더 오버헤드 없음 |
실시간성 | 서버가 클라이언트로 푸시 불가 | 실시간 데이터 푸시 가능 |
-
ws://
: 보안이 적용되지 않은 웹소켓 연결로, HTTP와 유사한 방식 -
wss://
: 보안 웹소켓 연결로, 데이터를 암호화함. HTTPS와 유사하며, SSL/TLS 암호화가 적용
- MQTT (Message Queuing Telemetry Transport): 퍼블리셔/서브스크라이버 구조를 사용하며, 낮은 대역폭에서도 실시간 데이터 전송이 가능하다. IoT 애플리케이션에서 많이 사용된다.
- SSE (Server-Sent Events): 서버에서 클라이언트로 데이터를 지속적으로 푸시할 수 있지만, 단방향 통신만 지원한다.
- XMPP (Extensible Messaging and Presence Protocol): 메시징과 상태 업데이트가 필요한 실시간 애플리케이션에 사용된다.
https://www.wallarm.com/what/xmpp-vs-websocket-which-to-use-for-applications
Node.js 환경에서 WebSocket 통신을 간편하게 사용할 수 있도록 도와주는 라이브러리
- 호환성: 모든 브라우저가 WebSocket을 지원하는 것은 아니며, 네트워크 방화벽이나 프록시가 WebSocket을 차단하는 경우도 있다. 이때, Socket.io는 다양한 폴백 옵션으로 안정적인 통신을 지원한다.
- 다양한 기능 제공: 재연결, 자동 연결 복구, 네임스페이스, 룸(room) 관리 등 WebSocket 단독으로 구현하기 복잡한 기능을 쉽게 제공한다.
- 편리한 API: 클라이언트와 서버 모두 간단하게 사용할 수 있는 API를 제공해 실시간 통신 애플리케이션을 쉽게 구축할 수 있다.
-
네임스페이스: 네임스페이스는 서로 다른 경로로 실시간 통신을 구성할 수 있게 해준다. 예를 들어,
/chat
,/news
와 같은 네임스페이스를 만들어서 채팅과 뉴스 업데이트를 별도로 관리할 수 있다.// 서버 const chat = io.of('/chat'); const news = io.of('/news'); chat.on('connection', (socket) => { console.log('Chat 네임스페이스 연결됨'); }); news.on('connection', (socket) => { console.log('News 네임스페이스 연결됨'); });
-
룸(Room): 같은 네임스페이스 내에서도 특정 그룹에만 데이터를 전송할 수 있다. 예를 들어, 특정 채팅방에 속한 사용자에게만 메시지를 전송할 수 있다.
// 특정 방에 사용자 추가 socket.join('room1'); // 특정 방에 있는 사용자에게만 메시지 전송 io.to('room1').emit('message', '이 메시지는 room1에만 전달됨');
-
이벤트 기반 통신: Socket.io는 이벤트 기반으로 통신이 이루어진다. 서버와 클라이언트는 서로 이벤트를 정의하고 해당 이벤트가 발생할 때 데이터를 전송할 수 있다.
// 서버에서 이벤트 정의 socket.on('chat message', (msg) => { console.log('메시지 수신:', msg); io.emit('chat message', msg); }); // 클라이언트에서 이벤트 트리거 socket.emit('chat message', 'Hello, world!');
-
이벤트 미들웨어
// 서버 측 미들웨어 예시 io.use((socket, next) => { // 인증 미들웨어 const token = socket.handshake.auth.token; verifyToken(token) .then(user => { socket.user = user; next(); }) .catch(err => next(new Error('Authentication error'))); }); // 특정 이벤트에 대한 미들웨어 socket.use(([event, ...args], next) => { // 이벤트 로깅 console.log(`Event: ${event}`, args); next(); }); // nest는 기존 데코레이터를 활용하면 됨
-
휘발성 메시지와 신뢰성 메시지
// 휘발성 메시지 전송 socket.volatile.emit('position', { x: 10, y: 20 }); // 신뢰성 있는 메시지 전송 (기본값) socket.emit('important', { data: 'must be delivered' }, (ack) => { if (ack) { console.log('메시지가 성공적으로 전달됨'); } });
-
재연결: Socket.io는 연결이 끊어졌을 때 자동으로 다시 연결을 시도한다. 개발자는 별도로 신경 쓸 필요 없이 안정적인 연결을 유지할 수 있다.
-
Redis 붙여서 웹소켓만을 위한 수평적 확장도 가능
-
클러스터링 / 배치 처리 / 디바운싱도 가능
⚓️ 사용자 피드백과 버그 기록
👷🏻 기술적 도전
📖 위키와 학습정리
✏️ 에디터
Novel이란?
Novel 스타일링 문제
에디터 저장 및 고려 사항들
📠 실시간 협업, 통신
Yorkie와 Novel editor 연동
YJS, Websocket, React-Flow
YJS, Socket.io
WebSocket과 Socket.io에 대해 간단히 알아보기
YJS 가이드 근데 이제 Socket.io를 곁들인
🏗️ 인프라와 CI/CD
NCloud CI CD 구축
BE 개발 스택과 기술적 고민
private key로 원격 서버 접근
nCloud 서버, VPC 만들고 설정
monorepo로 변경
⌛ 캐시, 최적화
rabbit mq 사용법
🔑 인증, 인가, 보안
passport로 oAuth 로그인 회원가입 구현
FE 로그인 기능 구현
JWT로 인증 인가 구현
JWT 쿠키로 사용하기
refresh token 보완하기
🧸 팀원 소개
⛺️ 그라운드 룰
🍞 커밋 컨벤션
🧈 이슈, PR 컨벤션
🥞 브랜치 전략
🌤️ 데일리 스크럼
📑 회의록
1️⃣ 1주차
킥오프(10/25)
2일차(10/29)
3일차(10/30)
4일차(10/31)
2️⃣ 2주차
8일차(11/04)
9일차(11/05)
11일차(11/07)
13일차(11/09)
3️⃣ 3주차
3주차 주간계획(11/11)
16일차(11/12)
18일차(11/14)
4️⃣ 4주차
4주차 주간계획(11/18)
23일차(11/19)
24일차(11/20)
25일차(11/21)
5️⃣ 5주차
5주차 주간계획(11/25)
29일차(11/25)
32일차(11/28)
34일차(11/30)
6️⃣ 6주차
6주차 주간계획(12/2)
37일차(12/3)