nodejs+express 다 중 채 팅 방 구축 절차

머리말
본 고 는 주로 필자 가 node 를 공부 할 때 연습 하 는 작은 프로젝트 로 서 며칠 의 여가 시간 을 들 여 코드 를 작성 하면 서 튜 토리 얼 을 쓰 는 과정 이다.node 이론 지식 을 많이 보고 실전 이 적은 친구 에 게 적용 된다 면 지금부터 시작 합 시다!
준비 작업
새 폴 더 chatroom
터미널 에 다음 명령 을 입력 하 십시오.절차 npm(설치 되 지 않 은 홈 페이지 에 node 와 npm 설치)에 따라 자동 으로 package.json 파일 을 생 성 합 니 다.
express 와 socket.io 설치
package.json 파일 은 다음 과 같 습 니 다.

//package.json
{
 "name": "chatroom",
 "version": "1.0.0",
 "description": "A simple chatroom",
 "main": "index.js",
 "scripts": {
  "test": "echo \"Error: no test specified\" && exit 1"
 },
 "repository": {
  "type": "git",
  "url": "git+https://github.com/ddvdd008/chatroom.git"
 },
 "keywords": [
  "chatroom",
  "nodejs",
  "express"
 ],
 "author": "ddvdd",
 "license": "ISC",
 "bugs": {
  "url": "https://github.com/ddvdd008/chatroom/issues"
 },
 "homepage": "https://github.com/ddvdd008/chatroom#readme"
}
express 와 socket.io 설치

npm install express --save 
npm install socket.io --save 
package.json 자동 추가 의존

"dependencies": {
 "express": "^4.16.2",
 "socket.io": "^2.0.4"
}
우 리 는 express 프레임 워 크 를 사용 하여 백 엔 드 서 비 스 를 쓰기 때문에 socket.io(Socket.io 는 실제로 WebSocket 의 부모 집합 이 고 Socket.io 는 WebSocket 과 폴 링 등 방법 을 봉 하여 상황 에 따라 방법 을 선택 하여 통신 할 것 이다.)클 라 이언 트 와 서버 에 지속 적 인 링크 를 만들어 서 통신 에 편리 합 니 다.
여기까지 준비 작업 이 거의 진행 되 지 않 았 으 니,다음은 우리 가 한 걸음 한 걸음 실현 하기 시작 하 자.
웹 서버 구축
express 생 성 서비스
node 학생 을 배 웠 으 니 낯 설 지 않 을 것 입 니 다.http.create Server 를 이용 하여 서버 를 간단하게 만 들 수 있 습 니 다.이번 에는 express 를 이용 하여 서 비 스 를 만 들 수 있 습 니 다.프로젝트 루트 디 렉 터 리 에 app.js 를 만 듭 니 다.

/**
* Created by ddvdd on 2018-02-07.
*/
const express = require('express'); 
const app = express();    //   express  ,   app。
const fs = require('fs');   //    node       ,      
const path = require('path');  //   node       ,       

app.listen(3000,()=>{    
 console.log("server running at 127.0.0.1:3000");  //     3000  ,              。
});

/**
* app.get(): express       ,    get  ,       node       ,    url  ,      app.get()   
* '/':    get       '/'    127.0.0.1:3000/      
* req          ,res          
*/
app.get('/',(req,res)=>{
 res.redirect('/chat.html');  // express      。           '/',           '127.0.0.1:3000/chat.html'   
});


/**
*        /chat.html           。
*/
app.get('/chat.html',(req,res)=>{
 fs.readFile(path.join(__dirname,'./public/chat.html'),function(err,data){  //    ,readFile              ,   path.join()      。
  if(err){
   console.error("  chat.html    ",err);     //    
   res.send('4 0 4');           //      ,      404
  } else {
   res.end(data);     //   data         , readFile                   data  。
  }         //   data     ,   html       
 })
});
보시 면 말씀 드 리 겠 습 니 다.이 express 프레임 워 크 도 그렇게 간편 하지 않 은 것 같 습 니 다.가장 간단 한 단일 페이지 를 보 내 는 방법 은 node 자체 http.create Server 와 크게 다 르 지 않 고 배 고 프 고 귀 찮 습 니 다.현재 로 서 는 그렇습니다.제 가 쉽게 이해 할 수 있 도록 하기 위해 서 입 니 다.express 는 매우 강력 한 중간 부품 을 제공 하여 정적 자원 파일 을 위탁 관리 해 주 었 습 니 다.다음은 저희 가 실현 하 겠 습 니 다.

app.use('/',express.static(path.join(__dirname,'./public'))); //      。
원래 의 것 대신:

app.get('/chat.html',(req,res)=>{
 fs.readFile(path.join(__dirname,'./public/chat.html'),function(err,data){  
  if(err){
   console.error("  chat.html    ",err);     
   res.send('4 0 4');           
  } else {
   res.end(data);     
  }         
 })
});
__dirname 은 현재 파일 이 있 는 절대 경 로 를 표시 하기 때문에 path.join 을 사용 하여 app.js 의 절대 경로 와 Public 를 합치 면 Public 의 절대 경 로 를 얻 을 수 있 습 니 다.path.join 을 사용 하 는 것 은.../public 라 는 이상 한 경 로 를 피하 기 위해 express.static 는 Public 폴 더 의 정적 자원 을 위탁 관리 합 니 다.127.0.0.1:3000/XXX/AAA 의 경로 만 있 으 면 Public 폴 더 에서 XXX 폴 더 에 있 는 AAA 파일 을 찾 아 브 라 우 저 에 보 냅 니 다.
지금 이 코드 에 대한 소개 가 많이 되 었 는 지,app.use()가 무엇 을 했 는 지 구체 적 으로 알 고 있 는 학생 은 여기에 갈 수 있 습 니 다.
socket.io 클 라 이언 트 와 서버 의 링크 만 들 기
위의 서 비 스 를 만 든 후에 우 리 는 socket.io 를 인용 하여 클 라 이언 트 와 서버 에 장기 적 인 링크 를 만들어 야 합 니 다.우 리 는 app.js 를 다음 과 같이 개조 합 니 다.

/**
* Created by ddvdd on 2018-02-07.
*/
const express = require('express'); 
const app = express();    //   express  ,   app。
const server = require('http').Server(app); 
const io = require('socket.io')(server);  // socket     app      。           socket.io    
const path = require('path');  //   node       ,       

server.listen(3000,()=>{    
 console.log("server running at 127.0.0.1:3000");  //     3000  ,              。 
}); 
...
...
app.use('/',express.static(path.join(__dirname,'./public')));  //      。 

/*socket*/ 
io.on('connection',(socket)=>{    //           
 
}); 
o.on 은 어떤 사건 을 감청 하 는 것 을 표시 합 니 다.이 사건 이 발생 하면 리 셋 함 수 를 촉발 합 니 다.connection'은 이벤트 이름 입 니 다.사용자 가 연결 하면 트리거 됩 니 다.현재 app.js 는 기본적으로 완성 되 었 습 니 다.루트 디 렉 터 리 에서 실 행 됩 니 다.
node app.js
>
현재 방문http://127.0.0.1:3000/static/chat.html:

어?아무것도 없어 요.그 건 쓸데없는 소리 가 아니 야!우 리 는 url 이 대응 하 는 정적 자원 을 요청 하지 않 았 습 니 다!
정적 html 추가
프로젝트 루트 디 렉 터 리 에 Public 폴 더 를 만 듭 니 다.Public 폴 더 에 chat.html 파일 을 새로 만 듭 니 다.

<!DOCTYPE html> 
<html lang="en"> 
<head> 
 <meta charset="UTF-8"> 
 <title>   </title> 
</head> 
<body> 
         
</body> 
</html> 
지금 우 리 는 페이지 를 새로 고 쳤 습 니 다.페이지 가 나 타 났 습 니 다.
>
여기 서 가장 간단 한 브 라 우 저 와 웹 서버 가 합작 하 는 프로젝트 가 이미 완성 되 었 습 니 다.그 다음 에 우 리 는 페이지 를 계속 보완 하고 서버 백 엔 드 에 업무 기능 을 추가 하여 여러 사람의 채 팅 방 을 실현 해 야 합 니 다.
기본 기능 실현
로그 인 기능 은 사용자 이름 이 필요 합 니 다.(비밀번호 가 필요 없습니다)이 사용자 이름 은 클 라 이언 트 서버 에 저장 되 어 있어 야 합 니 다.매번 정 보 를 전송 할 때마다 기본적으로 사용자 이름 을 포함해 야 한다.그렇지 않 으 면 누가 보 냈 는 지 모른다.
단체 채 팅 기능,우 리 는 정 보 를 가 려 서 우리 측 과 상대방 을 가 려 야 한다.
로그 인 기능 구현
login 페이지 재 구성
가장 기본 적 인 로그 인 인터페이스 는 사용자 이름 입력 상자 와 로그 인 단추 로 구성 되 어 있 습 니 다.

//chat.html
<!DOCTYPE html> 
<html lang="en"> 
<head> 
<meta charset="UTF-8"> 
<title>   </title>
<style>
 *{
  margin:0;
  padding:0;
  box-sizing: border-box;
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
 }
 .container{
  position: absolute;
  top:0;
  left:0;
  right:0;
  bottom:0;
  background-color: grey;
  padding: 50px;
 }
 .container .title{
  width:300px;
  margin: 0 auto;
  font-size: 30px;
  font-family: 'Franklin Gothic Medium';
  font-weight: bold;
  text-align: center;
  margin-bottom:50px;
 }
 .container .login-wrap{
  width:400px;
  padding: 20px;
  border: 1px solid #000;
  margin: 0 auto;
  text-align: center;
 }
 .login-wrap .user-ipt{
  width:360px;
  text-align: center;
  vertical-align: middle;
 }
 .login-wrap .login-button{
  width:60px;
  height:24px;
  line-height:20px;
  font-size: 14px;
  padding: 2px 0;
  border-radius: 5px;
  margin-top:10px;
 }
</style> 
</head> 
<body> 
 <div class="container">
  <div class="title">    ddvdd   </div>
  <div class="login-wrap">
   <div class="user-ipt">
    <span class="user-name">   :</span>
    <input id="name" class="name-ipt" type="text" />
   </div>
   <button id="loginbutton" class="login-button">  </button>
  </div>
 </div>
</body> 
</html>
간단 한 추가 스타일,정적 페이지 가 완성 되 었 습 니 다.다음 페이지 를 새로 고 칩 니 다.

로그 인 페이지 상호작용
어제 오후 에 반 까지 썼 는데...부서 가 갑자기 단체 로 모임 을 가 려 고 하 니 급히 코드 를 제출 하고 대충 일 을 끝 낼 수 밖 에 없다.오늘 아침 일찍 회사 에 와 서 계속 사 이 즈 를 드 리 도록 하 겠 습 니 다.
쓸데없는 소리 하지 말고 본론 으로 들 어가 서 이 상호작용 을 로그 인 합 니 다.사용자 가 서버 를 방문 하고 로그 인 에 성공 하면 온라인 로그 인 인원 을 계산 합 니 다.한 사용자 에 로그 인 할 때마다 서버 는 사용자 정 보 를 한 배열 에 저장 하고 서버 에 저장 합 니 다.여기 서 주의해 야 할 것 은 서버 가 사용자 가 로그 인 한 사용자 이름 을 검사 하고 검사 결 과 는 클 라 이언 트 에 게 돌아 갑 니 다.클 라 이언 트 는 검사 결 과 를 통 해 현재 페이지 가 채 팅 페이지 에 들 어 갈 지 여 부 를 변경 합 니 다.
위의 서버 와 클 라 이언 트 의 상호작용 은 모두 socket.io 를 통 해 통신 을 실현 합 니 다.전단 의 업무 상호작용 은 jquery 로 이 루어 집 니 다.Public 폴 더 에서 js 폴 더 를 새로 만 들 고 jquery-3.2.1.min.js,새 main.js 를 다운로드 합 니 다.그리고 chat.html 에 필요 한 sdk 도입:

<script src="js/jquery-3.2.1.min.js"></script>
<script src="js/main.js"></script>
//socket.io        
<script src="/socket.io/socket.io.js"></script>
sdk 를 도입 하면 main 의 js 에 로그 인 기능 을 추가 합 니 다.

//main.js
/**
* Created by ddvdd on 2018-02-08.
*/
$(function(){
 const url = 'http://127.0.0.1:3000';
 let _username = '';
 let _$inputname = $('#name');
 let _$loginButton = $('#loginbutton');

 let socket = io.connect(url);

 //     ,          
 let setUsername = () => {
  
  _username = _$inputname.val().trim(); //              

  //         
  if(_username) {
   socket.emit('login',{username: _username}); //       ,        ,         ,               
  }
  else{
   alert('      !');
  }
 };
 
 
 
 /*    */
 _$loginButton.on('click',function (event) { //         ,    ,        ,   setUsername  
  setUsername();
 });

 /*socket.io    */ 
 socket.on('loginResult',(data)=>{ 
  /** 
  *                      ,    
  *            ,     
  */ 
  if(data.code === 0) { 
   //     ,         
  }
  else if(data.code ===1){ 
   alert('     !'); 
  }
  else{
   alert('    !');
  }
 }) 

});
//app.js
/**
* Created by ddvdd on 2018-02-07.
*/
const express = require('express'); 
const app = express();    //   express  ,   app。
const server = require('http').Server(app); 
const io = require('socket.io')(server);  // socket     app      。           socket.io    
const path = require('path');  //   node       ,       

const users = [];     //            
let usersNum = 0;     //        

server.listen(3000,()=>{    
 console.log("server running at 127.0.0.1:3000");  //     3000  ,              。 
}); 


/**
* app.get(): express       ,    get  ,       node       ,    url  ,      app.get()   
* '/':    get       '/'    127.0.0.1:3000/      
* req          ,res          
*/
app.get('/',(req,res)=>{
 res.redirect('/static/chat.html');  // express      。           '/',           '127.0.0.1:3000/chat.html'   
});

/** 
* __dirname             ,      path.join app.js      public       public     。 
*  path.join        ././public         
* express.static       public         。 
*     127.0.0.1:3000/XXX/AAA       public     XXX     AAA          。 
*/ 
app.use('/static',express.static(path.join(__dirname,'./public')));  //      。 

/*socket*/ 
io.on('connection',(socket)=>{    //           
 
 socket.on('login',(data)=>{ 

  if(checkUserName(data)){
   socket.emit('loginResult',{code:1}); //code=1       
  }
  else{
   //             
   users.push({ 
    username: data.username, 
    message: [] 
   }); 
   socket.emit('loginResult',{code:0}); //code=0       
   usersNum = users.length; 
   console.log(`  ${data.username}    ,  ddvdd   ,        :${usersNum}`); 
  }
  
 }); 

 //          
 socket.on('disconnect',()=>{   //  ,            ,        
  usersNum = users.length; 
  console.log(`        :${usersNum}`); 
 }); 
}); 
//          
const checkUserName = (data) => {
 let isExist = false;
 users.map((user) => {
  if(user.username === data.username){
   isExist = true;
  }
 });
 return isExist;
}
위의 코드 는 다음 과 같은 몇 가 지 를 알 아야 합 니 다.
  • socket.on 은 감청 사건 을 표시 하고 그 다음 에 emit 가 보 낸 사건 을 받 아들 이 는 대상 을 되 돌려 줍 니 다.
  • socket.emit 는 사건 을 촉발 하고 대상 을 on 감청 사건 에 전달 합 니 다.
  • 저희 socket 연결 후 감청 트리거 사건 은 io.on('connection')의 리 셋 에 적 혀 있 습 니 다.이 사건 들 은 모두 연결 후 발생 한 것 이기 때문에 연결 이 끊 긴 사건 인 disconnect 도 연결 이벤트 에서 발생 합 니 다.연결 되 고 있 는 상태 가 없 는데 연결 이 끊 긴 것 이 어디 있 습 니까?
  • 서버 쪽 에 app.js 파일 만 있 지만 서로 다른 클 라 이언 트 가 연 결 된 후에 정 보 는 다 르 기 때문에 우 리 는 반드시 공용 정 보 를 저장 해 야 한다.예 를 들 어 모든 로그 인 사용자 의 배열 을 저장 하고 모든 사용자 가 보 낸 모든 정 보 를 외부 에 저장 해 야 하 며 connecion 에 저장 해 서 는 안 된다 는 것 을 이해 합 니 다.
  • 효과 표시:



    단체 채 팅 기능 실현
    간단 한 로그 인 기능 을 쓰 고 이 프로젝트 의 가장 중요 한 기능 단체 채 팅 을 쓰 겠 습 니 다.먼저 다음 페이지 를 처리 하 겠 습 니 다.기능 이 간단 하기 때문에 html 를 따로 만들어 채 팅 방 을 표시 하지 않 고 login 페이지 에 직접 쓰 고 class 이름 의 변 화 를 통 해 로그 인 후 채 팅 방 의 표 시 를 전환 합 니 다.
    채 팅 방 페이지 재 구성
    다음은 chat.html 를 수정 합 니 다.
    
    <!DOCTYPE html> 
    <html lang="en"> 
    <head> 
     <meta charset="UTF-8"> 
     <title>   </title>
     <script src="js/jquery-3.2.1.min.js"></script> 
     <script src="js/main.js"></script> 
     <script src="/socket.io/socket.io.js"></script> 
     <style>
      *{
       margin:0;
       padding:0;
       box-sizing: border-box;
       -webkit-box-sizing: border-box;
       -moz-box-sizing: border-box;
      }
      .container{
       position: absolute;
       top:0;
       left:0;
       right:0;
       bottom:0;
       background-color: darkgrey;
       padding: 50px;
       overflow-y: scroll;
      }
      .container .title{
       margin: 0 auto;
       font-size: 30px;
       font-family: 'Franklin Gothic Medium';
       font-weight: bold;
       text-align: center;
       margin-bottom:20px;
      }
      .container .login-wrap{
       width:400px;
       padding: 20px;
       border: 1px solid #000;
       margin: 0 auto;
       text-align: center;
      }
      .login-wrap .user-ipt{
       width:360px;
       text-align: center;
       vertical-align: middle;
      }
      .login-wrap .login-button{
      width:60px;
      height:24px;
      line-height:20px;
      font-size: 14px;
      padding: 2px 0;
      border-radius: 5px;
      margin-top:10px;
      }
      .chat-wrap .chat-content{
       width:100%;
       height:600px;
       background-color: whitesmoke;
       padding:10px;
      }
      .chat-wrap .send-wrap{
       margin-top: 20px;
      }
      .message-ipt{
       width: 200px;
       height: 100px;
       padding: 0 5px;
       vertical-align: bottom;
      }
      .chat-content p{
       display: block;
       margin-bottom: 10px;
      }
      .chat-content p .msg{
       display: inline-block;
       padding: 8px 11px;
       border-radius:6px;
      }
      .chat-content .self-message .msg{
       background-color:#d0e7ff;
       border: 1px solid #c9dfff;
      }
      .chat-content .other-message .msg{
       background-color:white;
       border: 1px solid #eee;
      }
      .chat-content .self-message{
       text-align:right;
      }
      .chat-content .other-message{
       text-align-last:left;
      }
     </style> 
    </head> 
    <body> 
     <div class="container">
      <div id="loginbox" class="login-wrap">
       <div class="title">  </div>
       <div class="user-ipt">
        <span class="user-name">   :</span>
        <input id="name" class="name-ipt" type="text" />
       </div>
       <button id="loginbutton" class="login-button">  </button>
      </div>
      <div id="chatbox" class="chat-wrap" style="display:none">
       <div id="content" class="chat-content">
        <!--      -->
       </div>
       <div class="send-wrap">
        <textarea rows="3" cols="20" id="chatmessage" class="message-ipt" type="textarea" placeholder="           "></textarea>
       </div>
      </div>
     </div>
    </body> 
    </html> 
    채 팅 방 으로 chatbox 용 기 를 추가 합 니 다.그룹 채 팅 상자 와 메 시 지 를 보 내 는 텍스트 상자 가 있 습 니 다.위의 login Result 리 셋 을 통 해 loginbox 를 숨 기 고 chatbox 를 표시 합 니 다.
    
    //       
    let showChatRoom = () => {
     /** 
      * 1.     ,         
      * 2.       
      */ 
     $('#loginbox').hide('slow');
     _$loginButton.off('click');
     /** 
     *       ,       ,     
     */
     $(`<div class="title">  ${_username}  ddvdd   </div>`).insertBefore($("#content")); 
     $("#chatbox").show('slow');
    }
    메시지 이벤트 전송 감청 메커니즘
    채 팅 은 반드시 클 라 이언 트 가 촉발 한 것 이기 때문에 메 시 지 를 보 내 는 것 은 클 라 이언 트 가 촉발 하고 서버 가 감청 하 는 것 이다.
    서버 는 메 시 지 를 보 내 는 이 벤트 를 감청 한 후 정 보 를 저장 하고 메 시 지 를 보 내 는 성공 이 벤트 를 모든 클 라 이언 트 에 게 방송 하여 모든 클 라 이언 트 에 게 정 보 를 전달 합 니 다.
    메시지 보 내기 sendmessage 이벤트
    
    //main.js
    //    
    let sendMessage = function () { 
     /** 
      *           ,     ,   sendMessage 
      *             
      */ 
     let _message = _$chattextarea.val(); 
     
     if(_message) { 
      socket.emit('sendMessage',{username: _username, message: _message}); 
     }
     else{
      alert('       !');
     } 
    }; 
    ...
    /*    */ 
    _$chattextarea.on('keyup',function (event) { 
     if(event.keyCode === 13) { 
      sendMessage(); 
      _$chattextarea.val(''); 
     } 
    });
    서버 측 감청 sendmessage 이벤트
    
    //app.js
    /** 
     *   sendMessage,           data  message,    。 
     */ 
    socket.on('sendMessage',(data)=>{ 
     for(let _user of users) { 
      if(_user.username === data.username) { 
       _user.message.push(data.message); 
       //        receiveMessage          -     
       io.emit('receiveMessage',data); 
       break; 
      } 
     } 
    }); 
    저 희 는 서버 를 옮 겨 다 니 는 사용자 배열 입 니 다.이 사용 자 를 찾 아 보 낸 정 보 를 저장 한 다음 에 receiveMessage 사건 을 모든 브 라 우 저 에 방송 합 니 다.sendmessage 는 connection 에 쓰 여 있 습 니 다.login 이외 의 것 입 니 다.왜 이렇게 하 는 지 이해 해 야 합 니 다.메 시 지 를 보 내 는 것 은 로그 인 할 때 하 는 일이 아니 라 연결 할 때 하 는 일 입 니 다.
    주의해 야 할 것 은 내 가 사용 하 는 것 은 io.emit 이다.그 는 모든 브 라 우 저 에 진정한 방송 이 고 socket.broadcast.emit 는 자신의 브 라 우 저 에 방송 되 지 않 는 다.
    클 라 이언 트 감청 receiveMessage 이벤트
    
    //main.js
    socket.on('receiveMessage',(data)=>{ 
     /** 
      * 
      *           
      */ 
     showMessage(data);
    }) 
    //    
    let showMessage = function (data) { 
     //               ,            
     if(data.username === _username){ 
      $("#content").append(`<p class='self-message'><span class='msg'>${data.message}</span><span class='name'> :${data.username}</span></p>`); 
     }else { 
      $("#content").append(`<p class='other-message'><span class='name'>${data.username}: </span><span class='msg'>${data.message}</span></p>`); 
     } 
    }; 
    여기에 쓰 세 요.저희 채 팅 방 의 기본 기능 이 완성 되 었 습 니 다.효 과 를 보 세 요!세 개의 브 라 우 저 를 열 고 각각 첫째,둘째,셋째 에 게 로그 인하 여"대 가 좋 습 니 다~저 는 슬 래 그 휘 입 니 다!"라 고 한 마디 보 냅 니 다.



    원본 주소:https://github.com/ddvdd008/chatroom

    좋은 웹페이지 즐겨찾기