Nodejs + socketio 를 활용하여 채팅을 구현해보자.
필수 설치 목록
- nodejs
- npm
- 이 곳에서 다운로드하면 nodejs, npm 모두 설치된다.
사용하게 될 스펙 및 중요 모듈
- Back-end : nodejs, express, socket.io,
- Front-end : jquery, bootstrap(css),
순서 (대기실 구성하기 - 일반 채팅)
- Express를 활용하여 웹서버 띄우기
- 프론트 그리기
- SocketIO를 를 붙여서 서버와 클라이언트(브라우저) 연결
다음편 순서 (채팅'방' 구현하기)
1. Express를 활용하여 웹서버 띄우기
원하는 폴더를 생성하고, 그 폴더에서
(~/working_folder)
$ npm init
을 실행한다.
npm init 을 하고나서 주로 enter로 다 넘기는데, entry point 설정은 app.js 로 설정한다. (개인마다 다른데, 보통 app.js를 많이 한다)
// ~/working_folder/package.json
{
"name": "mann-chat-web",
"version": "1.0.0",
"description": "",
"main": "app.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
npm init 을 한 뒤 위와 같이 package.json 파일이 생성된다.
(package.json 은 npm을 활용하여 소스코드를 관리할 때 생성되는 파일로, 각종 repository 및 명령어를 저장하는 등의 역할을 한다.)
package.json을 확인 한 후에, 다음으로 할 게 app.js (혹은 index.js)를 작성하는 것이다.
app.js 를 작성하기 전에, 이 튜토리얼에서는 express를 활용하여 서버를 구성할 것이므로,
// (~/working_folder)
$ npm intall --save express
위와 같이 express 모듈을 설치한다.
express 모듈을 설치한 뒤, app.js를 작성한다.
// ~/working_folder/app.js
const app = require('express')();
const http = require('http').createServer(app);
app.get('/', (req, res) => {
res.send("Hello world");
});
http.listen(3000, () => {
console.log('Connected at 3000');
});
위처럼 app.js를 작성하자.
- nodejs 위 express 모듈을 활용하여 웹서버를 띄우는 코드이며,
- port는 3000포트를 사용하게 될 서버이며,
- localhost:3000 에 접속하면 "Hello world"를 보내게 되어있음을 알 수 있다.
아직 socket.io 모듈을 활성화 시키지 않았다.
그럼 이제 app.js 로 실행하여 서버를 띄워보자
// (~/working_folder)
$ node app.js
해당 스크립트를 실행 후, 브라우저에서 localhost:3000 으로 접속하면, Hello World 메시지가 확인된다.
2. 프론트 그리기
다음으로는 채팅창을 그려보자. (index.html)
(bootstrap css 에 대해서는 크게 설명하진 않겠다. )
<!-- ~/working_folder/index.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Socket Tester</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<style>
#messages { list-style-type: none; margin: 0; padding: 0; }
#messages li { padding: 5px 10px; }
#messages li:nth-child(odd) { background: #eee; }
</style>
</head>
<body>
<div class="row">
<!-- 대기실 -->
<div class="col-lg-4">
<div class="card">
<div class="card-header">
대기실
</div>
<div class="card-body">
<form action="">
<div class="input-group mb-3">
<input type="text" class="form-control" id="m" autocomplete="off" />
<div class="input-group-append">
<button id="msg-send" class="btn btn-primary" placeholder="message">Send</button>
</div>
</div>
</form>
</div>
<div class="card-footer">
<ul id="messages"></ul>
</div>
</div>
</div>
<!-- 방선택 -->
<div class="col-lg-8"></div>
</div>
<script src="https://code.jquery.com/jquery-1.11.1.js"></script>
</body>
</html>
스타일에 대해 간략하게 얘기를 하자면,
- 부트스트랩 스타일링을 사용하여 작성하였고,
- 부트스트랩을 제외한 나머지 스타일링은 <style></style>에 담을 예정이다.
- 카드 컴포넌트를 활용해 채팅의 기본 UI를 구성하며,
- 대기실은 4/12(col-lg-4) 비율로 채팅방의 화면은 8/12(col-lg-8) 비율로 그려질 것이다.
이제 작성한 html 파일을 서버위에 올려보자.
기존에 작성했던, Get 라우터 중, "Hello wolrd" 를 전송하던 코드 블럭이 있다. 이젠 이 코드블럭에 "Hello world" 를 전송하는게 아닌 html파일을 전송하게 작성한다.
app.js 파일을 수정해보자.
// ~/working_folder/app.js
// 기존의 소스코드
app.get('/', (req, res) => {
res.send("Hello world");
});
// html 을 전송하는 소스코드
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html');
});
수정이 끝났다면, 다시
$ node app.js
를 실행하자. 그리고 localhost:3000 에 접속하면, 채팅방 ui 가 그려진 것을 확인할 수 있을 것이다.
3. SocketIO를 를 붙여서 서버와 클라이언트(브라우저) 연결
개인간의 채팅방은 제외하고, 우선 대기실에서 채팅을 할 수 있는 시스템을 구성해보자.
여기서 나오는 개념이 "io.emit" 이다.
io.emit 이란 현재 소켓 서버에 접속되어 있는 모든 사용자에게 메시지를 보내는 일을 한다.
소켓을 보내기/받기 하기 위해서는 먼저 서버와 클라이언트에서 설정해줘야할 것들이 있다.
우선 서버쪽을 먼저 보자.
socketio를 사용하기 위해선 socket.io 모듈이 필요하다.
socket.io 를 현재 package에 설치하도록하자.
$ npm install --save socket.io
서버
그리고 app.js 파일에 모듈을 선언하고, socketio 를 연동한다.
// app.js
//기존 코드
const app = require('express')();
const http = require('http').createServer(app);
// socket.io 모듈 사용 선언
const io = require('socket.io')(http);
..
...
.....
// 여기서 socket 은 개인 사용자 자신을 나타낸다 ( 사용자 개개인의 request source 라고 생각해도 될 듯 하다)
io.on('connection', (socket)=>{
socket.on('request_message', (msg) => {
io.emit('response_message', msg);
});
socket.on('disconnect', async () => {
console.log('user disconnected');
});
});
..
...
.....
클라이언트 쪽은 어떻게 될까?
클라이언트
socket.io 를 사용하기 위해선 javascript 내에서 socket.io.js 를 선언(로드)해주어야한다.
...
...
<!-- socket.io.js 를 로드한다 -->
<script src="/socket.io/socket.io.js"></script>
<script src="https://code.jquery.com/jquery-1.11.1.js"></script>
...
...
<script>
// socket 을 init 해준다
const socket = io();
</script>
(jqeury 이후에 로드해도 상관없다)
이제 클라이언트에서 서버에 메시지를 보내고, 받은 메시지를 대기실에 그려보자.
직접 코딩을 하기 이전에, 어떤 흐름인지 먼저 이해하고 넘어가자.
꼭 이해하고 넘어가자 !
- 클라이언트에서 request_message 프로토콜로 서버에 message를 보낸다.
(클라이언트에서 메시지 송출) - 서버에서 request_message프로토콜 request를 확인한다.
(서버에서 메시지 확인) - 서버에서 response_message 프로토콜을 모든 클라이언트에게 방출(emit)한다.
(서버에서 메시지 송출) - 클라이언트에서 response_message 프로토콜 response를 확인한다.
(클라이언트에서 메시지 확인) - 클라이언트에서 response_message 프로토콜 데이터를 활용하여 client UI 에 메시지를 그린다.
(클라이언트에서 결과 그리기)
참고 : 사실 socket.io 에는 request/response에 대한 개념이 크게 없다. 양방향 통신이므로, 어느쪽에서도 request 를 할 수 있다.
다만 request 라고 이름 지은 이유는, 패킷의 방향을 글로 이해하기 쉽게 하기 위함이다.
1. 클라이언트에서 메시지 송출
<script>
// 클라이언트에서 reuqest_message 프로토콜로 id='m' 의 input 값을 보낸다.
$('#msg-send').click(() => {
socket.emit('request_message', $('#m').val());
$('#m').val('');
return false;
});
</script>
jQuery를 사용하여, #msg-send 버튼이 클릭되었을 때, socket에 방출 명령어를 입력한다.
정해놓은 protocol 은 request_message 이며, #m input 의 value 값을 data 로 보낸다.
2. 서버에서 메시지 확인 & 서버에서 메시지 송출
// app.js
// request_message 프로토콜 listener
socket.on('request_message', (msg) => {
// response_message로 접속중인 모든 사용자에게 msg 를 담은 정보를 방출한다.
io.emit('response_message', msg);
});
서버에서 request_message 프로토콜으로 온, packet을 확인하고,
response_message 라는 프로토콜으로 메시지를 모든 유저(io.emit) 에게 방출한다.
3. 클라이언트 메시지 확인 & 클라이언트에서 결과 그리기
<script>
// 클라이언트에서 response_message 프로토콜 listener
socket.on('response_message', (res) => {
$('#messages').prepend($('<li>').text(res));
});
</script>
서버에서 전송된 response_message 프로토콜로 온 packet을 확인하고,
#messages 에 넘오온 패킷 data를 prepend(앞에 추가) 한다.
이제 모든 준비가 끝났다.
$ node app.js
를 실행하고, 브라우저에 localhost:3000으로 들어가서 채팅이 잘 되는지 확인해보도록하자.
혹시나 하는 마음에, 전체코드는 아래에 써두도록 하겠다.
+ (root folder)
|- app.js
|- index.html
|- package.json
package.json
{
"name": "lvup-server",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"bcrypt": "^5.0.0",
"express": "^4.17.1",
"express-validator": "^6.6.1",
"socket.io": "^2.3.0",
"ws": "^7.3.1"
}
}
app.js
const app = require('express')();
const http = require('http').createServer(app);
const io = require('socket.io')(http);
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html');
});
io.on('connection', (socket)=>{
socket.on('request_message', (msg) => {
// response_message로 접속중인 모든 사용자에게 msg 를 담은 정보를 방출한다.
io.emit('response_message', msg);
});
socket.on('disconnect', async () => {
console.log('user disconnected');
});
});
// TEST CODE GOES HERE
(async function(){
})();
http.listen(3000, () => {
console.log('Connected at 3000');
});
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Socket Tester</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<style>
#messages { list-style-type: none; margin: 0; padding: 0; }
#messages li { padding: 5px 10px; }
#messages li:nth-child(odd) { background: #eee; }
</style>
</head>
<body>
<div class="row">
<!-- 대기실 -->
<div class="col-lg-4">
<div class="card">
<div class="card-header">
대기실
</div>
<div class="card-body">
<form action="">
<div class="input-group mb-3">
<input type="text" class="form-control" id="m" autocomplete="off" />
<div class="input-group-append">
<button id="msg-send" class="btn btn-primary" placeholder="message">Send</button>
</div>
</div>
</form>
</div>
<div class="card-footer">
<ul id="messages"></ul>
</div>
</div>
</div>
<!-- 방선택 -->
<div class="col-lg-8"></div>
</div>
<script src="/socket.io/socket.io.js"></script>
<script src="https://code.jquery.com/jquery-1.11.1.js"></script>
<script>
$(() => {
/** Socket Starts **/
const socket = io();
// 클라이언트에서 reuqest_message 프로토콜로 id='m' 의 input 값을 보낸다.
$('#msg-send').click(() => {
socket.emit('request_message', $('#m').val());
$('#m').val('');
return false;
});
socket.on('response_message', (res) => {
$('#messages').prepend($('<li>').text(res));
});
});
</script>
</body>
</html>
'IT Study > Nodejs 채팅서버 튜토리얼' 카테고리의 다른 글
[Nodejs] 채팅구현하기 2 - SocketIO (1) | 2020.11.28 |
---|