저장을 습관화
NestJS - socket.emit, socket.on 연습 기록 본문
/views/index.hbs
{{! 템플릿 엔진 }}
{{! 서버 사이드에서 클라이언트 사이드(브라우저)로 보낼때 html로 렌더링 될 내용 }}
{{! https://docs.nestjs.com/techniques/mvc }}
<html>
<head>
<meta charset='utf-8' />
<title>{{data.title}}</title>
<link href='css/styles.css' rel='stylesheet' />
{{! public부터 시작하는 절대 경로로 지정해야지, 상대 경로로는 적용되지 않는다. }}
{{! main.ts에서 선언한 내용에 따라 진행되기 때문이다. }}
</head>
<body>
<h1>Hello World!</h1>
<div id='hello_stranger'></div>
<div id='chatting_box'></div>
<form id='chat_form'>
<input placeholder='Chat...' />
<button type='submit'>Chat</button>
</form>
{{! babel - 최신 자바스크립트 문법을 브라우저에서 사용가능하게 지원해줌 }}
<script src='https://unpkg.com/@babel/standalone/babel.min.js'></script>
{{! polyfill, 자바스크립트를 지원하지 않는 브라우저에서도 자바스크립트 메서드 등을 사용할 수 있게 해줌 }}
<script
src='https://polyfill.io/v3/polyfill.min.js?features=default%2Ces2015%2Ces2016%2Ces2017%2Ces2018%2Ces2019'
></script>
{{! socket.io - 웹 클라이언트와 서버 간 실시간 양방향 통신을 지원해줌}}
<script
src='https://cdn.socket.io/3.1.3/socket.io.min.js'
integrity='sha384-cPwlPLvBTa3sKAgddT6krw0cJat7egBga3DJepJyrLl4Q9/5WLra3rrnMcyTyOnh'
crossorigin='anonymous'
></script>
<script src='js/scripts.js'></script>
{{! public부터 시작하는 절대 경로로 지정해야지, 상대 경로로는 적용되지 않는다. }}
{{! main.ts에서 선언한 내용에 따라 진행되기 때문이다. }}
</body>
</html>
/public/js/scripts.js
const socket = io('/'); // socket.io의 메소드를 사용하기 위한 준비
const getElementById = (id) => {
return document.getElementById(id) || null;
};
// DOM에서 특정 id를 가진 HTML 요소를 찾는다.
// id를 가진 HTML 요소가 존재하지 않는다면(undefined의 경우) null를 반환한다.
// get DOM element
const helloStrangerElement = getElementById('hello_stranger');
const chattingBoxElement = getElementById('chatting_box');
const formElement = getElementById('chat_form');
const helloUser = () => {
const username = prompt('What is your name?');
socket.emit('new_user', username, (data) => {
console.log(data);
});
// emit은 '보내는 행위'
// 서버에서 클라이언트로, 클라이언트에서 서버로 보낼 때도 emit
// prompt를 통해 입력받은 내용을 변수 username에 할당하고,
// 이벤트 'new_user'를 찾아간다. 여기서는 /src/chats/chats.gateway.ts이다.
console.log(username);
socket.on('hello_user', (data) => {
console.log(data);
});
// on은 '받는 행위
// 서버가 보낸 데이터를 클라이언트가 받거나,
// 클라이언트가 보낸 데이터를 서버가 받는 경우가 on
// chats.gateway.ts의 'handleNewUser'메소드에서 socket.emit을 통해 보낸 데이터를 받아 이벤트를 수행한다.
};
const init = () => {
helloUser();
};
init();
emit은 '보내는 행위'
서버에서 클라이언트로, 클라이언트에서 서버로 보낼 때 모두 emit
on은 '받는 행위'
서버가 보낸 데이터를 클라이언트가 받거나,
클라이언트가 보낸 데이터를 서버가 받는 경우 모두 on
/src/chats/chats.gateway.ts
import {
SubscribeMessage,
WebSocketGateway,
MessageBody,
ConnectedSocket,
} from '@nestjs/websockets';
import { Socket } from 'socket.io';
@WebSocketGateway()
export class ChatsGateway {
@SubscribeMessage('new_user')
// /public/script.js의 함수 helloUser에서 socket.emit 메소드로 보낸 데이터를 받는다.
handleNewUser(
@MessageBody() username: string,
@ConnectedSocket() socket: Socket,
) {
console.log(socket.id); // 소켓의 아이디
// 모든 소켓은 개별적인 아이디를 가지며, 연결이 끊어질때마다 이 아이디는 사라진다.
// 새로 연결하면 새로운 아이디를 받는다.
console.log(username);
socket.emit('hello_user', 'Hello ' + username);
// 다시 emit으로 'hello_user'이벤트를 향해 보내거나
return 'this is return for emit!';
// return을 통해 값을 반환할 수도 있다.
}
}
양방향 통신 연결로 발생하는 모든 소켓은 개별적인 아이디를 가진다.
연결이 끊어지면 이 아이디는 사라지며,
같은 서버와 같은 클라이언트더라도 새롭게 연결하면 새로운 아이디를 가지는 소켓을 받는다.
실행 화면
- scripts.js
const helloUser = () => {
const username = prompt('What is your name?');
socket.emit('new_user', username, (data) => {
console.log(data);
});
console.log(username);
socket.on('hello_user', (data) => {
console.log(data);
});
};
함수 helloUser에서 발생시킨 프롬프트로 사용자의 이름을 묻고,
입력받은 내용을 socket.emit('new_user')을 'new_user'를 향해 보낸다.
- chats.gateway.ts
@WebSocketGateway()
export class ChatsGateway {
@SubscribeMessage('new_user')
handleNewUser(
@MessageBody() username: string,
@ConnectedSocket() socket: Socket,
) {
console.log(socket.id);
console.log(username);
socket.emit('hello_user', 'Hello ' + username);
return 'this is return for emit!';
}
}
console.log(socket.id)와 console.log(username)의 결과가 출력되고
socket.emit('new_user', username, (data) => {
console.log(data);
});
console.log(username); // <- 이게 먼저 실행되었다.
socket.on('hello_user', (data) => {
console.log(data);
});
console.log(username)의 결과인 ctrs_socket_test가 출력 되었고
socket.emit('hello_user', 'Hello ' + username의 결과로
scripts.js의 socket.on('hello_user')이벤트를 실행시켜
socket.on('hello_user', (data) => {
console.log(data);
Hello ctrs_socket_test가 출력되었다.
socket.emit('hello_user', 'Hello ' + username);
return 'this is return for emit!';
마지막으로
return 'this is return for emit!'의 결과로 scripts.js의 socket.emit 메소드가 종료되며
this is return for emit!가 출력었다.
함수나 컨트롤러-서비스의 관계에서처럼
promise가 없다면 실행한 순서대로가 아닌 먼저 처리되는 순서대로 비동기처리된다.
'공부 > node.js' 카테고리의 다른 글
NestJS - socket.broadcast.emit() 브로드캐스팅 방식 (0) | 2023.10.20 |
---|---|
NestJS - 네임스페이스와 생명주기(Lifecycle) 메모 (0) | 2023.10.19 |
NestJS - multer를 사용하여 S3에 데이터 저장 1 (0) | 2023.10.14 |
NestJS - multer를 이용한 미디어 파일 서비스 (0) | 2023.10.09 |
NestJS - Swagger를 사용해서 API 문서 만들기 (0) | 2023.10.04 |