Search

웹소켓

WebSocket이란?

HTTP는 클라이언트가 요청하면 서버가 응답하는 구조이다.
반면 WebSocket은 클라이언트 ↔ 서버 간에 양방향 통신이 가능하게 해주는 프로토콜이다.
서버가 클라이언트에게 실시간으로 메세지를 전송한다.
연결을 유지하며 데이터를 주고받는다. (HTTP보다 빠르다)

NestJS에서의 WebSocket

NestJS는 @nestjs/websockets 패키지를 설치하여 WebSocket을 쉽게 사용할 수 있게 해준다.
@WebSocketGateway 데코레이터를 통해 해당 클래스를 WebSocket 서버로 등록해준다.
@WebSocketGateway(port?: number, options?: GatewayOptions) export class ExampleGateway { }
TypeScript
복사
옵션
설명
예시
port
게이트웨이가 바인딩될 포트 번호 생략 시 HTTP 서버와 같은 포트를 사용한다.
@WebSocketGateway(3001)
namespace
특정 namespace로 클라이언트를 구분한다. 클라이언트들이 다른 경로(/chat, /notification 등)로 접속하게끔 나누는 단위
@WebSocketGateway({ namespace: '/chat' })
cors
socket.io 서버 CORS 설정을 할 수 있다. NestJS HTTP 서버의 CORS 설정과는 별개이다.
@WebSocketGateway({ cors: { origin: '*' } })
transports
클라이언트 ↔ 서버 통신 방식 설정 (websocket, polling 등)
@WebSocketGateway({ transports: ['websocket'] })
path
커스텀 path로 WebSocket 서버를 노출할 수 있음
@WebSocketGateway({ path: '/ws' })

socket.io 서버의 옵션

NestJS는 WebSocket을 지원할 때 내부적으로 socket.io 를 사용한다. @WebSocketGateway 데코레이터의 옵션으로 들어가는 cors설정은 socket.io 서버 생성자에 전달되는 것이다.
@WebSocketGateway({ cors: { origin: '*' } }) 위 코드는 const io = new Server(httpServer, { cors: { origin: '*' } }); 이 코드와 같다.
TypeScript
복사

transports 옵션

transports 옵션에는 크게 polling과 websocket이 있다.
기본 옵션은 ['polling', 'websocket'] 으로 처음에는 polling으로 시작해서 가능하면 websocket으로 업그레이드하는 것이다.
만약 웹소켓만 쓰고 싶다면 [’websocket’]으로 polling만 할거라면 [’polling’]으로 설정하면 된다.
방화벽이나 프록시 문제로 웹소켓이 연결이 안 될 수도 있어 운영단계에서는 보통 기본 옵션을 사용한다.

연습 예제 코드

import { ConnectedSocket, MessageBody, OnGatewayConnection, OnGatewayDisconnect, SubscribeMessage, WebSocketGateway, WebSocketServer, } from '@nestjs/websockets'; import { Server, Socket } from 'socket.io'; // ExampleGateway를 WebSocket 서버로 등록 // 내부적으로 socket.io 서버 인스턴스를 생성 @WebSocketGateway({ namespace: '/example', transports: ['websocket'], cors: { origin: '*', }, }) export class ExampleGateway implements OnGatewayConnection, OnGatewayDisconnect { // Gateway 클래스에 Socket.IO의 서버 인스턴스를 주입해주는 데코레이터 // 클라이언트에게 직접 이벤트를 보내는 등 작업을 수행 @WebSocketServer() io: Server; handleConnection(client: Socket): any { const data = client.handshake.query; console.log(`client 연결 : ${client.id}, message: ${data.name}`); } handleDisconnect(client: Socket): any { console.log(`client 연결 끊김 : ${client.id}`); } @SubscribeMessage('message') handleTestMessage( @MessageBody() message: string, @ConnectedSocket() client: Socket, ) { const username = client.handshake.query.name[0]; const sendMessage = `${username} : ${message}`; this.io.emit('message', sendMessage); } }
TypeScript
복사