본문 바로가기

Back-End/Node.js

socket.io를 이용한 채팅 구현

반응형

주요 기능

  1. 접속하면 알림 출력
  2. 닉네임 변경 가능
  3. 닉네임 변경했을 때 알림 출력
  4. 유저가 떠났을 경우 알림 출력

 


express-generator를 이용해 새 프로젝트를 생성한 후, 이동하여 채팅을 만드는 데 필요한 socket.io, Pug를 설치한다.

express socket-chat
cd socket-chat && npm install
npm install link socket.io
npm install pug

 

우선 기본적으로 같은 페이지에 접속한 사람들과 채팅이 가능해야 한다.

추가 기능으로, 닉네임 변경을 하거나 새로운 사람이 접속했을 때, 접속이 끊어졌을 때도 채팅창에 알림 문구가 뜨도록 만들어보자. 

또한 일반 HTML이 아닌 Pug를 이용해 만들어보자. 또 채팅창의 모양을 결정하는 스타일 부분도 CSS로 따로 빼낼 예정이다.

기본 HTML만 사용하면 투박한 느낌이 나므로 깔끔한 디자인을 위해 부트스트랩도 적용했다. 부트스트랩은 프론트엔드 프레임워크로, 웹사이트를 만들 때 좀 더 쉽게 꾸밀 수 있도록 도와준다.

 

먼저 서버를 작동시키는 server.js를 생성하자. express-generator로 생성했을 경우 서버 코드는 www로 분리되어 있지만, 이번 채팅 예제에서는 따로 www로 빼지 않고 server.js 코드 하나에 서버 코드를 모두 작성하도록 하자. 따라서 npm sart가 아닌 node server로 서버를 구동시킨다.

 

server.js

//server.js
var express = require('express');
var app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var path = require('path');

app.set('views', './views');
app.set('view engine', 'pug');
app.use(express.static(path.join(__dirname, 'public')));

app.get('/', function(req, res){
    res.render('chat'); //루트 페이지로 접속시 chat.pug 렌더링함
});

var count = 1;

io.on('connection', function(socket){   
    // (1) 채팅방에 접속했을 때 (웹 페이지 접속시 자동으로 이벤트 실행)
    console.log('user connected: ', socket.id); //사용자 id
    var name = "익명" + count++;
    socket.name = name; //익명n
    io.to(socket.id).emit('create name', name); //'create name'이벤트를 발생시켜 클라이언트에게 전송
    //io.to(socket.id).emit : 서버가 해당 socket id에만 이벤트를 전달함

    // (2) 채팅방 접속이 끊어졌을 때
    socket.on('disconnect', function() {
        //서버 콘솔에 나간 사용자를 찍음
        console.log('user disconnected: '+ socket.id + ' ' + socket.name);
    });

    // (3) 메시지를 보냈을 때 - data(name, text) 받음
    socket.on('send message', function(name, text){
        var msg = name + ' : ' + text;
        socket.name = name;
        console.log(msg);
        io.emit('receive message', msg);    //msg(name : text)데이터를 클라이언트로 'receive message'이벤트를 보냄
    });
})

http.listen(3000, function(){   //3000번 포트로 서버 연결
    console.log('server on..');
})

views/chat.pug

doctype 5
html
  head
    title= 'Chat'
    link(rel='stylesheet', href='/stylesheets/style.css')
    link(rel="stylesheet", href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css", integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous")
    script(src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js", integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous")  // 위 link와 이 script는 부트스트랩 연결
    script(src='/socket.io/socket.io.js')
    script(src='//code.jquery.com/jquery-1.11.1.js')
  body
    center
      div
        button.btn.btn-info(type='button') Goorm 채팅방  
        //- 부트스트랩 버튼
      div
        textarea#chatLog.form-control(readonly='')  
        //- 부트스트랩 textarea
      form#chat
        input#name.form-control(type='text')  
        //- 부트스트랩 input
        input#message.form-control(type='text')  
        //- 부트스트랩 input
        button.btn.btn-primary(type='submit') 전송  
        //- 부트스트랩 버튼
      #box.box
			
    script.
      var socket = io(); 
    
      // (1) 전송 버튼을 누를 때 
      $('#chat').on('submit', function(e){   
      socket.emit('send message', $('#name').val(), $('#message').val());
      //send message이벤트 발생해주면서 name input값과 message input값을 전달시킴
      $('#message').val('');    //message input값을 초기화함
      $('#message').focus();    //메시지에 커서를 둠
      e.preventDefault();
      });
			
      // (2) 이름 셋팅
      socket.on('create name', function(name){     
      $('#name').val(name); //서버로부터 받은 name값을 name input에 넣음
      });
      
      // (3) 메시지를 받았을 때
      socket.on('receive message', function(msg){  
      $('#chatLog').append(msg+'\n');   //서버로부터 받은 msg(name+text)를 출력함
      $('#chatLog').scrollTop($('#chatLog')[0].scrollHeight);   //채팅창에 스크롤이 생기면 가장 아래쪽으로 스크롤을 내려줌
      });

public/stylesheets/style.css

#chatLog{
	width: 50%; 
	height: 500px;
}
#name{ 
	width: 10%; 
}

#message{ 
	width: 35%; 
}

.btn.btn-info{
	width: 50%;
	height: 45px;
	font-size: 20px;
}

 

결과

 

 

추가 기능

이제 전체적인 틀을 잡았으니, 주요 기능을 추가하자.

  1. 접속하면 알림 출력
  2. 닉네임 변경 가능
  3. 닉네임 변경했을 때 알림 출력
  4. 유저가 떠났을 경우 알림 출력

server.js

var express = require('express');
var app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var path = require('path');

app.set('views', './views');
app.set('view engine', 'pug');
app.use(express.static(path.join(__dirname, 'public')));

app.get('/', function(req, res){
    res.render('chat'); //루트 페이지로 접속시 chat.pug 렌더링함
});

var count = 1;

io.on('connection', function(socket){   
    // (1) 채팅방에 접속했을 때 (웹 페이지 접속시 자동으로 이벤트 실행)
    console.log('user connected: ', socket.id); //사용자 id
    var name = "익명" + count++;
    socket.name = name; //익명n
    io.to(socket.id).emit('create name', name); //'create name'이벤트를 발생시켜 클라이언트에게 전송
    //io.to(socket.id).emit : 서버가 해당 socket id에만 이벤트를 전달함
    io.emit('new_connect', name);   //io.emit : 사용자 전부에게 전달

    // (2) 채팅방 접속이 끊어졌을 때
    socket.on('disconnect', function() {
        //서버 콘솔에 나간 사용자를 찍음
        console.log('user disconnected: '+ socket.id + ' ' + socket.name);
        io.emit('new_disconnect', name);    //to.emit : 사용자 전부에게 전달
    });

    // (3) 메시지를 보냈을 때 - data(name, text) 받음
    socket.on('send message', function(name, text){
        var msg = name + ' : ' + text;
        //닉네임을 바꿨을 때
        if(name != socket.name) 
            io.emit('change_name', socket.name, name);
        socket.name = name;
        console.log(msg);
        io.emit('receive message', msg);    //msg(name : text)데이터를 클라이언트로 'receive message'이벤트를 보냄
    });
})

http.listen(3000, function(){   //3000번 포트로 서버 연결
    console.log('server on..');
})

 

views/chat.pug

 

doctype 5
html
  head
    title= 'Chat'
    link(rel='stylesheet', href='/stylesheets/style.css')
    link(rel="stylesheet", href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css", integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous")
    script(src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js", integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous")  // 위 link와 이 script는 부트스트랩 연결
    script(src='/socket.io/socket.io.js')
    script(src='//code.jquery.com/jquery-1.11.1.js')
  body
    center
      div
        button.btn.btn-info(type='button') Goorm 채팅방  
        //- 부트스트랩 버튼
      div
        textarea#chatLog.form-control(readonly='')  
        //- 부트스트랩 textarea
      form#chat
        input#name.form-control(type='text')  
        //- 부트스트랩 input
        input#message.form-control(type='text')  
        //- 부트스트랩 input
        button.btn.btn-primary(type='submit') 전송  
        //- 부트스트랩 버튼
      #box.box
			
    script.
      var socket = io(); 
    
      // (1) 전송 버튼을 누를 때 
      $('#chat').on('submit', function(e){   
      socket.emit('send message', $('#name').val(), $('#message').val());
      //send message이벤트 발생해주면서 name input값과 message input값을 전달시킴
      $('#message').val('');    //message input값을 초기화함
      $('#message').focus();    //메시지에 커서를 둠
      e.preventDefault();
      });
			
      // (2) 이름 셋팅
      socket.on('create name', function(name){     
      $('#name').val(name); //서버로부터 받은 name값을 name input에 넣음
      });
      
      // (3) 메시지를 받았을 때
      socket.on('receive message', function(msg){  
      $('#chatLog').append(msg+'\n');   //서버로부터 받은 msg(name+text)를 출력함
      $('#chatLog').scrollTop($('#chatLog')[0].scrollHeight);   //채팅창에 스크롤이 생기면 가장 아래쪽으로 스크롤을 내려줌
      });

      // (4) 닉네임 변경했을 때
      socket.on('change_name', function(oldname, name){
      $('#chatLog').append('<알림>' + oldname + '님이' + name + '님으로 닉네임을 변경했습니다.\n');
      });

      // (5) 채팅방 접속이 끊어졌을 때
      socket.on('new_disconnect', function(name){
      $('#chatLog').append('<알림>' + name + '님이 채팅방을 떠났습니다.\n');
      });

      // (6) 채팅방에 접속했을 때
      socket.on('new_connect', function(name){
      $('#chatLog').append('<알림>' + name + '님이 채팅방에 접속했습니다.\n');
      });

결과

반응형

'Back-End > Node.js' 카테고리의 다른 글

Node.js 입력 받기  (0) 2020.09.18
빙고 게임 만들기  (0) 2020.09.09
웹 애플리케이션에 실시간 기능 부여하기 [3/3]  (0) 2020.09.09
웹소켓  (0) 2020.09.09
Socket.IO  (0) 2020.09.08