ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Node.js] 실시간 채팅 서비스 만들기(5) - 채팅 기능 구현
    Node.js 2018. 5. 31. 16:16

    안녕하세요



    이번 시간에는 지난 강좌에 이어 본격적으로 채팅 기능을 구현해보도록 하겠습니다!




    이전 강좌의 응용이므로 크게 어렵지않습니다!



    [목차]


    1. 채팅 기능 설계

    2. 서버 코드 작성

    3. 클라이언트 코드 작성

    4. 테스트






    채팅 개발을 위해 간단히 정리하고 시작합시다!



    우리가 개발할 채팅은 실시간 채팅입니다.


    누가 새로 들어왔는지, 누가 나갔는지 알 수 있도록 기능을 구현할 예정이구요


    기본적인 채팅 기능을 구현할 예정입니다.





    이벤트 명은 미리 정의하고 시작하도록 하겠습니다!



    message: 클라이언트가 서버로 메시지 전송

    update: 서버에서 받은 메시지 다른 클라이언트에게 전송(메시지 또는 정보)

    connectUser: 새로운 유저 접속을 서버에게 알림


    접속 종료부분은 update로 통일하여 클라이언트에게 전달할 예정입니다!







    클라이언트와 서버에서 주고받는 메시지(알림)의 형식은 아래의 형식으로 정의하도록 하겠습니다

    type에는 message(기본 메시지), connect(접속 알림), disconnect(채팅 종료 알림) 3가지를 사용할 예정입니다!






    서버코드를 작성해봅시다!




    소켓 접속부분에 위 코드와 동일하게 작성해주세요!

    (또는 아래 서버 소스코드 다운로드)


    app.js





    서버에서 newUser, message, disconnect 이벤트를 수신합니다.

    (disconnect 이벤트는 기본 이벤트입니다)


    클라이언트가 접속을 성공하면 클라이언트에서 newUser 이벤트를 발생시킬겁니다.

    이벤트 발생과 함께 닉네임도 같이 서버로 전송하도록 해서 서버의 socket 안에 이름을 따로 저장해둡니다.


    socket.name = name


    이 부분이 클라이언트로부터 받은 닉네임을 소켓에 저장시키는 코드입니다.


    닉네임 정보를 받았으니 접속되어있는 다른 유저에게도 접속사실을 알려야합니다.



    io.sockets.emit('update' 데이터)


    를 통해 다른 유저들에게도 알립니다.

    type은 connect로 지정하고 메시지를 보내줍니다.







    message 이벤트는 클라이언트에서 메시지를 입력하고 발생시키는 이벤트입니다.

    유저가 보내는 메시지는 모두 type이 message인 데이터로 위에서 정의했습니다.


    타입과 메시지부분만 있으면 안되고 누가 보냈는지 알리기 위해 data.name = socket.name 으로 

    소켓에 저장해두었던 이름을 데이터에 추가해줍니다!


    A, B, C 세 사람이 채팅을 하고 있다고 가정하고

    A라는 사람이 메시지를 전송했으면 A 본인은 메시지를 받지 않고 B, C만 메시지를 수신하면 됩니다.


    socket.broadcase.emit('이벤트명', 전달할데이터)


    를 사용하면 본인을 제외한 나머지 유저에게 데이터를 전송할 수 있습니다!



    io.sockets.emit() = 모든 유저(본인 포함)

    socket.broadcast.emit() = 본인을 제외한 나머지 모두


    상황에 맞는 방법을 사용하시면 됩니다!



    이제 서버측 작업은 마무리되었습니다.



    마지막으로 클라이언트 소스코드를 수정해봅시다!





    클라이언트 소스코드는 지난 시간에 사용했던 HTML, CSS는 그대로 두고 JS 파일만 아래와 같이 수정합니다.




    서버와 접속이 되어 connect 이벤트가 발생되면

    닉네임을 입력받습니다.


    만약 닉네임이 빈칸이면 이름을 '익명' 으로 지정하고 서버에게 닉네임과 함께 newUser 이벤트를 발생시킵니다.




    클라이언트에는 메시지를 수신해야하기 때문에 socket.on('update' ...) 가 있습니다.

    일단 임시로 데이터만 확인하기 위해 콘솔에 출력하도록 구현했습니다.




    마지막으로 클라이언트는 메시지를 전송도 하기 때문에 전송 기능도 구현했습니다.


    message 이벤트를 발생시키면서 동시에 입력된 메시지도 서버에게 전달합니다.

    유저가 보내는 메시지는 기본 메시지이므로 타입은 message 입니다.





    이제 저장시키고 테스트를 진행해봅시다.




    웹 브라우저 창을 2개 띄우고 닉네임을 서로 다르게 입력해줍니다.


    저는 A유저, B유저라고 정했습니다.




    구글 크롬 기준 F12를 누르면 개발자 도구가 열립니다.


    Console 탭을 눌러서 콘솔을 확인해봅시다!




    서로 메시지를 입력하고 전송하면 정상적으로 주고받는 모습을 보실 수 있습니다.


    본인이 보낸 메시지는 로그에 안남고 상대방이 보낸 메시지만 로그에 남습니다!



    또한 누가 접속했는지 서버에서 알림으로 알려줍니다.




    클라이언트말고 서버의 콘솔창도 확인해보세요



    2명의 유저가 주고받는 메시지 기록이 모두 보입니다.


    정상적으로 작동하네요 ㅎㅎ



    마지막으로 유저 한명이 나갔다고 가정하고 브라우저 창 하나를 꺼줍니다.



    그러면 유저가 나갔다고 남아있는 유저들에게 알림을 전송합니다.



    기본적인 채팅 기능은 모두 구현이 되었습니다!



    콘솔로 메시지를 확인하기 너무 불편하기 때문에 HTML, CSS, JS를 수정해서 뷰로 확인할 수 있도록 구현하시면 됩니다!


    아래에 예제 파일도 올리도록 하겠습니다.






    예제를 사용하시려면 기존의 index.html, index.js, index.css 세 파일을 지우고 아래 파일로 교체해주세요!


    index.html

    index.js

    index.css



    서버코드는 동일하게 사용하시면 됩니다!












    여러분들이 더 심플하게 꾸미시거나 새로운 방법으로 채팅창을 꾸미시면 됩니다!






    채팅 기능에 관련된 모든 강좌가 끝났습니다!


    2명이 아닌 여러명이 접속해도 모두 다함께 채팅이 가능합니다!


    또한 그룹 채팅도 가능합니다!




    그룹 채팅에 대해서는 나중에 한번 올려보도록 하겠습니다!




    오늘까지 진행한 내용 모두 제 Github에 업로드 되어있습니다!




    오늘 진행한 내용은 아래 링크에 업로드 되어있습니다.


    https://github.com/leegeunhyeok/node-chat/tree/chapter_5





    감사합니다.

    댓글 46

    • 이전 댓글 더보기
    • 나이스코딩 2018.12.03 13:44

      안녕하십니까 선배님! 졸업프로젝트를 진행하고 있는데 app.js에서 no1,no2,no3,no4...변수로 가져온 api데이터를 html파일의
      Math.round(요기) // data-min= 요기
      요기 이 부분에 가져오고 싶은데 어떻게 처리해야 할까요?ㅠㅠ
      ——————app.js———————-
      let request = require('request');
      let cheerio = require('cheerio');

      const $url = 'http://kradata.kra.co.kr:8082/service/api15/getOpenDataList';

      const $KEY = '';

      const $meet = '1';
      const $hr_no = '037703';
      const $api_url = $url + '?meet=' + $meet + '&hr_no=' + $hr_no + '&ServiceKey=' + $KEY;

      console.log($api_url);




      request($api_url, function(err, res, body) {
      $ = cheerio.load(body);

      $('item').each(function(idx){
      let no1 = $(this).find('hrName').text();
      let no2 = $(this).find('winRateT').text();
      let no3 = $(this).find('qnlRateT').text();
      let no4 = $(this).find('winRateY').text();
      let no5 = $(this).find('recentRcDist').text();
      let no6 = $(this).find('chaksunT').text();
      let no7 = $(this).find('chaksunY').text();
      let no8 = $(this).find('chaksun_6').text();

      console.log(`경주마 이름 : ${no1} \n 통산 승률: ${no2}, 통산 복승률: ${no3}, 최근 1년 승률: ${no4} \n 최근경주거리: ${no5}, 통산착순상금: ${no6}, 최근1년착순상금: ${no7}, 최근6개월수득상금: ${no8}`);


      });
      });

      —————————Html——————————-
      <script>

      $(window).load(function() {
      doughnutWidget.options = {
      container: $('#container'),
      width: 100,
      height: 100,
      class: 'myClass',
      cutout: 50
      };

      doughnutWidget.render(data());

      setInterval(init, 2000);
      });

      function init() {
      doughnutWidget.render(data());
      }

      function data() {
      var data = {
      통산승률: {
      val: Math.round(60),
      color: '#57B4F2',
      click: function(e) {
      console.log('hi');
      }
      },
      통산복승률: {
      val: Math.round(80),
      color: '#6DED5C'
      },
      최근1년승률: {
      val: Math.round(90),
      color: '#E63329',
      link: 'http://www.google.com'
      }
      };

      return data;
      }
      </script>


      </script>
      <script type="text/javascript"
      src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
      </script></div>
      <div class="jquery-script-clear"></div>
      </div>
      </div>







      <div class='container'>
      <div class='header'>
      <h1 class='title'>강토마</h1>
      </div>





      <div id="container" class="half-left" role="group"></div>


      <div class='section half-right'>

      <div class='numscroller-info-top'>최근경주거리</div>
      <div class='numscroller numscroller-big-bottom' data-slno='1' data-min='0' data-max='2000' data-delay='10' data-increment="900">0</div>
      </div>
      <div class='section half-right'>
      <div class='numscroller-info-top'>통산착순상금</div>
      <div class='numscroller numscroller-big-bottom' data-slno='1' data-min='0' data-max='243900000' data-delay='10' data-increment="1000000">0</div>
      </div>


      • BlogIcon 이근둥 2018.12.20 13:14 신고

        추출한 데이터를 클라이언트로 받아오려면 서버를 구축한 후 클라이언트와 통신해야합니다. 한 번 Nodejs express api 서버에 대해 알아보면 좋을 것 같습니다

    • 김은채 2018.12.24 01:25

      정말 큰 도움이 되었습니다. 하나 하나 자세히 설명해주셔서 어렵지 않게 따라할 수 있었어요! ㅠㅠ

    • BlogIcon 프린커 2019.03.23 09:46 신고

      감사합니다. 좋은 정보 였고 공부 할 수 있었습니다.

    • cocoden8 2019.04.04 17:19

      감사합니다. 예제 따라서 편하게 할 수 있었어요ㅎ

    • 로리 2019.05.25 02:05

      정말 큰 도움이 되었어요! 너무 감사합니다!

    • 최현호 2019.05.31 12:48

      궁금한점 이 있어서 질문올립니다
      제가 지금 대학교 수업프로젝트를 진행중인데,
      저희만든 html및 jsp 사이트에 이튜토리얼을 바꿔서 적용시키려고 했는데,
      여기서 접속하려면 node app.js해야되잖아요? 이걸 따로 안하고 실시간 채팅이 될수 있게하는방법이 없을까요?
      아니면 그냥 사이트 키기전에 알아서 실행되게 하는거라던지 방법이 없을까요?

      • BlogIcon 이근둥 2019.06.10 19:49 신고

        JSP의 경우 socketio가 따로 없나봅니다.. "JSP/Java 웹소켓" 을 검색해보시면 socketio처럼 실시간 소켓통신을 하는 예제가 있으니 확인해보시면 될 것 같습니다

    • 채팅서버 2019.07.17 00:12

      혹시 이 채팅방의 인원제한도 할 수 있을까요??
      채팅방의 최대 인원이 5명이면 5명 이후로는 disconnect될 수 있게요..!

      • BlogIcon 이근둥 2019.07.17 00:14 신고

        접속자 인원을 파악한 후 서버측에서 특정 이벤트를 발생시켜주고 클라이언트에서 이를 받고 처리를 하면 될 것 같습니다

    • 초급개발자 2019.09.05 18:30

      서로 다른피씨에서 이렇게 채팅을 구현 할때는 어케해야되나요

      • BlogIcon 이근둥 2019.09.05 18:36 신고

        로컬호스트 대신 서버의 IP주소로 접속하면 됩니다. 주로 실제 서비스를 하는 경우 서버의 공인 IP로 접속을 하게 됩니다. (공유기, 라우터 등에 의해 포트가 막혀있으면 외부 사용자들이 접속할 수 없으니 이 부분은 따로 확인해보셔야 합니다)

    • 김박사 2019.10.09 21:21

      궁금한 부분이 있어서 질문드립니다.
      이렇게 구현한 채팅서버에 관계형데이터베이스를 붙여서 채팅내용이랑 채팅자를 저장하고 싶은데 어떻게 해야되나요?

    • 이쿠에쿠 2019.10.16 19:25

      채팅창에서 채팅이 입력되면 자동으로 스크롤을 내리려면 어케해야되나요

    • 알파카 2019.11.03 21:38

      덕분에 쉽게 채팅을 구현해볼 수 있었습니다. 감사합니다 :)!!

    • shelden 2020.01.24 14:30

      감사합니다. 덕분에 채팅 프로그램 구현했어요!

    • 조금만 2020.01.28 22:58

      정말 감사합니당^^ 너무 감사합니당~

    • 2020.02.04 21:56

      비밀댓글입니다

      • BlogIcon 이근둥 2020.02.04 21:58 신고

        채팅방에 참여하기 전에 서버측에서 세션을 확인한 후 인증된 상태면 입장, 인증되지 않았다면 로그인 페이지로 리다이렉션 시켜주는 방식으로 구현하시면 될 듯 합니다.

        로그인 성공 시 데이터베이스나 기타 데이터에서 사용자 정보를 불러와 채팅 닉네임으로 사용할 수 있도록 구현하시면 됩니다

      • 2020.02.04 22:05

        비밀댓글입니다

      • BlogIcon 이근둥 2020.02.07 11:35 신고

        네네 맞습니다

      • 2020.02.07 13:14

        비밀댓글입니다

    • 김국평 2020.02.18 19:06

      각각의 프로세스는 다르고, 네트워크는 같은 IP Address를 사용하고 Port는 서로 상이하게 하려면 어떻게 구현하면 될까요?

    • 21년차개발고수 2020.04.15 15:51

      DID 장비 동기화에 node.js 를 활용해볼까 하다가 본 강좌를 참고하게 되었습니다.
      님의 강좌는 제가 본 강좌중에 별 다섯 개 최고 입니다.
      아마도 교육이나 강의를 해 보신 분이 아닐까 싶습니다.
      어려운 작업을 쉽게 단계별로 학습할 수 있도록 도와주는 체계적 개요와 구성,핵심과 응용의 대비 구별, 자세한 예제와 다양한 활용, 친절한 QNA 답변까지 완벽하네요.
      큰 도움이 되었고 감사드립니다.

      • BlogIcon 이근둥 2020.04.15 16:51 신고

        큰 그림을 보여드리기 위해 상세한 설명이 생략되어 다소 부족한 부분이 있을텐데, 좋게 평가해주셔서 정말 감사합니다!

    • channn 2020.04.20 20:24

      정말 쉽게 따라할 수 있도록 요약해서 잘 써주신 것 같아요. 쭉 따라가기만 해도 흐름을 쉽게 파악할 수 있네요. 정말 감사합니다!

    • ㅇㅇ 2020.06.17 17:26

      처음에
      반갑습니다라고 팝업창 같은거 뜨면서
      유저명 입력하는거요 ...
      그건 localhost 접속하자마자 원래 뜨도록 되어야하는거죠??? 인터넷 익스프롤러로했을때 안되고 , 크롬 ,엣지는 뜨네요 ..익스프롤러 어떤부분을 수정해야 뜨게할수있나요?

      • BlogIcon 이근둥 2020.06.25 14:31 신고

        익스플로러인 경우 기타 호환성 문제로 코드 실행 도중 오류가 발생했을 수 있습니다.

        개발자도구 콘솔에서 오류 내용을 확인해보시고 알려주시면 확인해보도록 하겠습니다.

    • ㅇㅈㅇ 2020.09.14 12:14

      도움이 많이 되었습니다. 좋은 강의 정말 감사합니다!! 두고 두고 볼 것 같아요ㅠㅠ!!!

    • ㅈㅇㅅ 2020.10.03 18:12

      <script src="/socket.io/socket.io.js"></script>
      이것은 어딜 참조하는것인가요?

Designed by Tistory.