server
가 메시지를 받은 뒤,메시지를 각 사용자들에게 보내는 방식의 채팅 앱 만들기~!📲src
├─ index.html
├─>css
├┴style.css
├─>js
├┴chat.js
│
app.js
app.js
const express = require("express");
const http = require("http");
const app = express();
const path = require("path");
const server = http.createServer(app);
const socketIO = require("socket.io");
const io = socketIO(server);
app.use(express.static(path.join(__dirname,"src"))); // __dirname: 프로젝트 폴더 이름
const PORT = process.env.PORT || 5000;
io.on("connection",(socket)=>{
console.log("연결이 이루어 졌습니다.");
});
// app.listen(PORT, ()=>console.log(`server is running ${PORT}`));
server.listen(PORT, ()=>console.log(`server is running ${PORT}`));
src
-index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>chat app</title>
</head>
<body>
<h1>hello</h1>
<!-- express사용하고 있기 때문에 절대경로 사용해서 다운 받은 라이브러리에 접근가능. -->
<script src="/socket.io/socket.io.js"></script>
<script src="js/chat.js"></script>
</body>
</html>
src
-js
-chat.js
"use strict"
const socket = io();
// 정상적으로 불러와졌는지 확인
console.log(socket);
package.json
생성npm init -y
- app의 중요한 정보를 담고 있음.
- 설정이나 라이브러리들의 기록 같은 것을 담아 놓는 중요한 파일.
라이브러리 설치
npm install express socket.io moment
- 시간을 알려주기 위해 moment도 같이 설치.
node_modules
생성- git 등에 공유할 때 ignore을 시켜서
node_modules
은 보내지 않고package.json
파일만 올리면 어떤 라이브러리를 설치 했는지 공유할 수 있다.
express 라이브러리 가져오기
const express = require("express");
- 필요한 express 라이브러리를 가져오고, 그 라이브러리를 변수
express
에 담음.require
를 쓰게 되면 자동적으로node_modules
를 보기 때문에,
필요한express
만 적어줘도 경로 없이 가져올 수 있게 됨.
변수에 담기
const app = express();
express
를 실행한 내용을app
에 담음.
path
불러오기const path = require("path")
- 서버 주소를 명확하게 쓰기 위해서
path
라는node.js
의 기본 모듈 불러오기
서버가 보여줄 파일 지정
app.use(express.static(path.join(__dirname,"src")));
- 서버가 실행이 되면 서버가 보여줄 파일들을 지정.
path
사용으로 url을 쉽게 만들수 있게 됨.
PORT
생성const PORT = process.env.PORT || 5000;
- 서버를 실행하기 위해서는
PORT
가 필요함.process
환경에PORT
가 지정이 되어 있다면, 그PORT
를 사용하고, 아니라면5000번 PORT
사용.
서버 실행
app.listen(PORT, ()=>console.log(`server is running ${PORT}`));
app.listen(포트,명령);
nodemon
라이브러리 설치npm install -g nodemon
- 기존에는 js파일에 변경이 있을 때 마다 새롭게 실행해줘야하는 불편함이 있음.
- 번거러우므로
nodemon
이라는 라이브러리 설치- js 파일에 변경이 있을 때 마다 자동으로 실행시켜줌.
http
불러오기const http = require("http");
socket.io
를 받을 수 있도록 서버 쪽에서 세팅을 해줘야함.- 현재
web socket
이라서http
를 통해서 이루어져야만 한다.http node.js
의 기본 모듈인http
를 불러서 사용.
변수
server
생성const server = http.createServer(app);
http
불러 온 후에server
라는 변수 생성express
로 구현한app
을 담아서express
가 결국http
를 통해서 실행될 수 있도록 구현.server.listen(PORT, ()=>console.log(`server is running ${PORT}`));
(app
->server
변경 )
socket.io
불러오기const socketIO = require("socket.io");
socket.io
라이브러리를 불러와서 변수에 담아줌.
server
담아주기const io = socketIO(server);
- 생성한 변수
socketIO
에server
담아주기.- 생성한
io
를 통해서 보낸 메시지나 정보를 받아 와서 사용, 제어를 한다.
정보를
socket
에 담기io.on("connection",(socket)=>{ console.log("연결이 이루어 졌습니다."); });
connection
이 이루어지면 연결이 이루어졌을 때 연결에 대한 정보를socket
에 담음.socket
에 담겨있는 정보에 접근해서 내용을 다루게 된다.console.log("연결이 이루어 졌습니다.");
로 연결 확인을 한다.
연결 확인
- 연결이 완료된것을 확인할 수 있다!
혹시나 라이브러리 불러오는 것이 안된다면?
cdnjs_socket.io에 들어가서 코드 카피후에 html파일에 붙여넣으면 된다 😮
app.js
const express = require("express");
const http = require("http");
const app = express();
const path = require("path");
const server = http.createServer(app);
const socketIO = require("socket.io");
const io = socketIO(server);
app.use(express.static(path.join(__dirname,"src"))); // __dirname: 프로젝트 폴더 이름
const PORT = process.env.PORT || 5000;
// 서버에서 받아주기
io.on("connection",(socket)=>{
socket.on("chatting",(data)=>{
console.log(data)
io.emit("chatting", `오오옹 안농 ${data}`)
})
});
// app.listen(PORT, ()=>console.log(`server is running ${PORT}`));
server.listen(PORT, ()=>console.log(`server is running ${PORT}`));
src
-js
-chat.js
"use strict"
const socket = io();
socket.emit("chatting", "hi gyomni"); // socket 객체를 이용해서 메시지 보내기
// 받아 줄 때는 socket.on 사용.
socket.on("chatting", (data)=>{
console.log(data)
})
// 정상적으로 불러와졌는지 확인
console.log(socket);
chat.js
socket 객체를 이용해서 메시지 보내기
socket.emit("chatting", "hi gyomni")
socket.emit("채팅 아이디", "보낼 내용")
app.js
서버에서 받아주기
io.on("connection",(socket)=>{ socket.on("chatting",(data)=>{ console.log(data) }) });
io.on("connection",(socket)=>{ socket.on("채팅 아이디",(클라이언트에서 보낸 내용을 파라미터로 받음)=>{ }) });
- 서버를 준비하고 프론트에서 새로고침하면
hi gyomni
가 서버에 출력된 것을 확인할 수 있다.
서버에서 출력되고 서버에서 메시지 되돌려주기
app.js
io.on("connection",(socket)=>{ socket.on("chatting",(data)=>{ console.log(data) io.emit("chatting", `오오옹 안농 ${data}`) }) });
string
형태로 전체메시지 보내기- 프론트에서도 서버가 보낸 내용을 받을 수 있음.
- 여기까지만 하면 프론트에서는 변화가 없으므로 아래처럼 작성하면 프론트에서 확인할 수 있다.
chat.js
socket.on("chatting", (data)=>{ console.log(data); })
- 받아 줄 때는
socket.on
사용.data
에는 서버에서 보낸 내용이 담기게 된다. (이름 무관)- 첫번째 인자 : 채팅아이디
- 두번째 인자 : 실행할 내용
-> 새로고침을 하면
emit
을 통해서 보내게 되고(chat.js
)
서버에서 다시emit
을 통해서 프론트엔드 쪽으로 보내고(app.js
)
프론트는 메시지를 확인 (chat.js
)할 수 있게 된다.
기본적인 버튼 만들어서 전송하고, 서버에서 받은 내용을 핸들링 하기
app.js
const express = require("express");
const http = require("http");
const app = express();
const path = require("path");
const server = http.createServer(app);
const socketIO = require("socket.io");
const io = socketIO(server);
app.use(express.static(path.join(__dirname,"src"))); // __dirname: 프로젝트 폴더 이름
const PORT = process.env.PORT || 5000;
// 서버에서 받아주기
io.on("connection",(socket)=>{
socket.on("chatting",(data)=>{
console.log(data)
io.emit("chatting", `오오옹 안농 ${data}`)
})
});
// app.listen(PORT, ()=>console.log(`server is running ${PORT}`));
server.listen(PORT, ()=>console.log(`server is running ${PORT}`));
src
-index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>chat app</title>
</head>
<body>
<div class="wrapper">
<div class="user-container">
대화명 : <input type="text" id="nickname">
</div>
<div class="display-container">
<ul class="chatting-list">
<!-- 받은 내용을 li로 넣기 -->
</ul>
</div>
<div class="input-container">
<input type="text" class="chatting-input">
<button class="send-button">전송</button>
</div>
</div>
<!-- express사용하고 있기 때문에 절대경로 사용해서 다운 받은 라이브러리에 접근가능. -->
<script src="/socket.io/socket.io.js"></script>
<script src="js/chat.js"></script>
</body>
</html>
src
-js
-chat.js
"use strict"
const socket = io();
const nickname = document.querySelector("#nickname");
const chatList =document.querySelector(".chatting-list");
const chatInput = document.querySelector(".chatting-input")
const sendButton = document.querySelector(".send-button")
sendButton.addEventListener("click",()=>{
const param = {
name: nickname.value, // input이라서 value 접근 가능.
msg : chatInput.value,
};
socket.emit("chatting",param);
} )
// 받아 줄 때는 socket.on 사용.
socket.on("chatting", (data)=>{
const li = document.createElement("li");
li.innerText = `${data.name}님의 메시지 : ${data.msg}`;
chatList.appendChild(li);
})
// 정상적으로 불러와졌는지 확인
console.log(socket);
이벤트 걸기
chat.js
sendButton.addEventListener("click",()=>{ const param = { name: nickname.value, // input이라서 value 접근 가능. msg : chatInput.value, }; socket.emit("chatting",param); } )
- 닉네임과 내용을 서버로 보내기.
- 데이터를 오브젝트로 보낸다.
param
를 보내주면 서버에서 받을 수 있다.
서버에서 받는 부분 확인
app.js
io.on("connection",(socket)=>{ socket.on("chatting",(data)=>{ console.log(data) io.emit("chatting", `오오옹 안농 ${data}`) }) });
- 서버에 오브젝트 형태로 전송이 된 것을 확인할 수 있음.
io.on("connection",(socket)=>{ socket.on("chatting",(data)=>{ io.emit("chatting", data) }) });
- 받은 오브젝트를 그대로 다시 보내주기 (나머지 부분은 클라이언트에서 처리)
- 데이터에는 오브젝트가 담겨있기 때문에 전송해주면 나온 내용을 받을 수 있다.
->{name: 'gyomni', msg: 'hihi'}
socket
을 받았을 때chatList
에li
를 만들고 넣기
chat.js
socket.on("chatting", (data)=>{ const li = document.createElement("li"); li.innerText = `${data.name}님의 메시지 : ${data.msg}`; chatList.appendChild(li); })
http://localhost:5000/
으로 들어가서 새로운 페이지에 닉네임과 대화를 작성하니web socket
으로 채팅이 된다.
대략적인 style을
css
로 작성
- 하드 코딩으로 내용을 대략적으로 채워넣고 스타일을 잡았다.
chat.js
에서li
생성하는 부분을 수정해야 한다!
app.js
const express = require("express");
const http = require("http");
const app = express();
const path = require("path");
const server = http.createServer(app);
const socketIO = require("socket.io");
const moment = require("moment");
const io = socketIO(server);
app.use(express.static(path.join(__dirname,"src"))); // __dirname: 프로젝트 폴더 이름
const PORT = process.env.PORT || 5000;
// 서버에서 받아주기
io.on("connection",(socket)=>{
socket.on("chatting",(data)=>{
const {name, msg} = data;
io.emit("chatting",{
name,
msg,
time: moment(new Date()).format("h:mm A")
})
})
});
// app.listen(PORT, ()=>console.log(`server is running ${PORT}`));
server.listen(PORT, ()=>console.log(`server is running ${PORT}`));
src
-index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>chat app</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div class="wrapper">
<div class="user-container">
<label for="nickname">대화명</label>
<input type="text" id="nickname">
</div>
<div class="display-container">
<ul class="chatting-list">
</ul>
</div>
<div class="input-container">
<span>
<input type="text" class="chatting-input">
<button class="send-button">전송</button>
</span>
</div>
</div>
<!-- express사용하고 있기 때문에 절대경로 사용해서 다운 받은 라이브러리에 접근가능. -->
<script src="/socket.io/socket.io.js"></script>
<script src="js/chat.js"></script>
</body>
</html>
src
-js
-chat.js
"use strict"
const socket = io();
const nickname = document.querySelector("#nickname");
const chatList =document.querySelector(".chatting-list");
const chatInput = document.querySelector(".chatting-input");
const sendButton = document.querySelector(".send-button");
const displayContainer = document.querySelector(".display-container");
chatInput.addEventListener("keypress", (e)=>{
if(e.keycode ===13){
send();
}
})
function send(){
const param = {
name: nickname.value, // input이라서 value 접근 가능.
msg : chatInput.value,
};
socket.emit("chatting",param);
}
sendButton.addEventListener("click",send)
// 받아 줄 때는 socket.on 사용.
socket.on("chatting", (data)=>{
const {name, msg, time} = data;
const item = new LiModel(name, msg, time);
item.makeLi()
// 스크롤 밑으로
displayContainer.scrollTo(0, displayContainer.scrollHeight)
})
function LiModel(name, msg, time){
this.name = name;
this.msg = msg;
this.time = time;
this.makeLi = ()=>{
const li = document.createElement("li");
li.classList.add(nickname.value === this.name ? "sent" : "received")
const dom = ` <span class="profile">
<span class="user">${this.name}</span>
<img class="image"src="http://placeimg.com/50/50/any" alt="any">
</span>
<span class="message">${this.msg}</span>
<span class="time">${this.time}</span>`;
li.innerHTML = dom;
chatList.appendChild(li);
}
}
// 정상적으로 불러와졌는지 확인
console.log(socket);
chat.js
function LiModel(name, msg, time){ // 초기화 할당 // 아래 만든 makeLi라는 메서드에서 값들에 접근해서 사용하기 위해. this.name = name; this.msg = msg; this.time = time; this.makeLi = ()=>{ const li = document.createElement("li"); // 내가 보낸 메시지는 오른쪽으로 오도록 li.classList.add(nickname.value === this.name ? "sent" : "received") const dom = ` <span class="profile"> <span class="user">${this.name}</span> <img class="image"src="http://placeimg.com/50/50/any" alt="any"> </span> <span class="message">${this.msg}</span> <span class="time">${this.time}</span>`; li.innerHTML = dom; chatList.appendChild(li); } }
index.html
의li
부분을 가져와서 넣어주기.socket.on("chatting", (data)=>{ const {name, msg, time} = data; // LiModel 인스턴스화 const item = new LiModel(name, msg, time); item.makeLi() // 스크롤 밑으로 displayContainer.scrollTo(0, displayContainer.scrollHeight) })
- 서버에서 데이터를 받았을 때 마다
LiModel
을 찍어냄.
발송 시간 처리
app.js
const moment = require("moment"); . . . io.on("connection",(socket)=>{ socket.on("chatting",(data)=>{ const {name, msg} = data; io.emit("chatting",{ name, msg, time: moment(new Date()).format("h:mm A") // 현재시간 가져오기 }) }) });
moment
불러오기emit
하는 부분에 시간 넘겨주기- 여기서
data
는chat.js
의param
데이터format("YYYY-MM-DD HH:mm:ss")
-> 년 - 월 - 일 - 시 - 분 - 초 순서대로!
스크롤 처리
chat.js
const displayContainer = document.querySelector(".display-container"); . . . socket.on("chatting", (data)=>{ const {name, msg, time} = data; const item = new LiModel(name, msg, time); item.makeLi() // 스크롤 밑으로 displayContainer.scrollTo(0, displayContainer.scrollHeight) })
displayContainer
의 스크롤 위치를 읽어서 위치를 스크롤의 높이로 이동.
enter로 전송하기
chatInput.addEventListener("keypress", (e)=>{ if(e.keycode ===13){ send(); } }) function send(){ const param = { name: nickname.value, // input이라서 value 접근 가능. msg : chatInput.value, }; socket.emit("chatting",param); }
keypress
이벤트가 발생할 때, 키코드 값이 13(= enter) 이면 실행.
ngrok
설치npm install -g ngrok
- 외부 사람들이 접속할 수 있또록 만들어주는 라이브러리.
- 간단하게 테스트 한 것을 공유할 때 유용!
ngrok
실행ngrok http 5000
- 5000->현재보여주고 싶은 PORT
- 실행 전에
node.js
실행해주기- Forwarding된 주소 = 외부에서 접속할 수 있는 주소
http://f2d1-125-137-175-211.ngrok.io
오....뭔가 잘못된듯......?...
일단 http://localhost:5000/
로 실행해보면 !
잘 실행된다 👏👏 위 오류는 한번 찾아와야겠다@!!