728x90
Reference
더보기
해당 포스팅은 노마드코더의 '줌 클론코딩' 강좌를 보고 공부한 내용을 작성한 포스팅입니다.
구현 예정 기능
- 실시간 채팅 보내기 / 받기
- 닉네임 설정
- 방 설정
- 채팅 이벤트
- HTTP protocol
http://...
- Client - Server
- request <-> response 과정
- Real-Time 은 아니다.
- request가 이루어져야만 서버는 답하는 형식
- 응답이 이루어지고 나서 요청 및 응답 데이터는 소멸
- WebSocket protocol
ws://...
- 웹 브라우저에만 국한되는 시스템은 아니다.
- Client - Server 연결뿐만 아니라 Server - Server 연결도 가능하다.
- Client - Server
- request <-> accept/non accept
- Client와 Server가 연결
- Server가 요청을 받으면 Client와 Server는 연결이 된다.
→ (연결된 동안은 데이터 계속 유지)
→ 연결이 된 동안에는 Client 요청이 없어도 Server 에서도 데이터 전송 가능
- ws npm 패키지
1. WebSocket 이벤트 메서드
해당 부분 전체 소스 코드
📢 코드 이해도를 위해 이벤트 함수는 모두 익명 함수로 작성했습니다!
- WebSocket 에도 js 처럼 특정 이벤트를 발생시키는 키워드가 존재한다.
- http 프로토콜은 프론트엔드의 요청이 있어야지만 백엔드가 응답을 할 수 있는 구조이지만 ws 프로토콜은 프론트엔드의 요청이 없어도 백엔드 응답 가능(양방향 통신)
const wss = new WebSocket.Server({ server }); // webSocket 서버 생성
// param socket : 서버와 브라우저간의 연결 정보
function handleConnection(socket) {
console.log(socket)
}
wss.on("connection" , handleConnection); // on method : 이벤트를 기다림
| 📄 server.js
import http from "http";
import WebSocket from "ws";
import express from "express";
const app = express();
app.set("view engine", "pug");
app.set("views", __dirname + "/views");
app.use("/public", express.static(__dirname + "/public"));
app.get("/", (_, res) => res.render("home"));
app.get("/*", (_, res) => res.redirect("/"));
const handleListen = () => console.log(`Listening on http://localhost:3000`);
const server = http.createServer(app);
const wss = new WebSocket.Server({ server });
const sockets = [];// fake database
// 어느 브라우저에서 연결했는지를 알기 위함
// socket : 브라우저와의 연결 정보
wss.on("connection", (socket) => { // 브라우저와 연결 성공 시
sockets.push(socket); // 다른 브라우저 연결시, socketsArray에 추가해줌
console.log("Connected to Browser ✅");
socket.on("close", () => { // 브라우저 연결 실패 시
console.log("Disconnected from the Browser ❌");
});
socket.on("message", (message) => { // 브라우저로 부터 메시지 받았을 시
sockets.forEach((aSocket) => aSocket.send(message));
// 각 브라우저 각각을 aSocket으로 놓고 메시지 전송(sockets에서 꺼내와서 전송)
});
});
server.listen(3000, handleListen);
| 📄 app.js
const messageList = document.querySelector("ul");
const messageForm = document.querySelector("form");
const socket = new WebSocket(`ws://${window.location.host}`);
socket.addEventListener("open", () => {
console.log("Connected to Server ✅");
});
socket.addEventListener("message", (message) => { // 백엔드로부터 메시지를 받았을 경우
console.log("New message: ", message.data);
});
socket.addEventListener("close", () => {
console.log("Disconnected from Server ❌");
});
function handleSubmit(event) {
event.preventDefault();
const input = messageForm.querySelector("input");
socket.send(input.value);
input.value = "";
}
messageForm.addEventListener("submit", handleSubmit);
🌟 socket의 의미
- app.js(프론트엔드) : 생성한 ws 객체 (브라우저 당 개별적으로 존재)
- server.js(백엔드) : 프론트엔드와의 연결상태
📢 ws 버전에 따라 문자가 나타나지 않는 문제 해결!
➡ 서버측에서 message.toString('utf-8') 로 String으로 변환해준다.
2. 닉네임 설정
해당 부분 전체 소스 코드
- nickname, message를 구분하기 위해
nickname
타입과message
타입으로 넘겨준다.
{
type: "nickname", (닉네임)
payload: "tom" (닉네임으로 할 이름)
}
{
type: "message", (채팅)
payload: "Hello!" (채팅 내용)
}
- 🌟 socket.send 메서드의 데이터 타입이
String
이므로 변환 작업을 수행한다! Json
으로 데이터를 주고 받으면 안좋은 이유 : 데이터를 받는 서버가js
코드가 아닐 경우 충돌이 발생할 우려가 있다.
└webSocket
은 어디에서든 사용할 수 있는 API이기 때문에 데이터 타입에 영향을 받아서는 안된다.
- 프론트엔드 :
String
➡Json
변환 ➡ 다시Json
->String
- 백엔드 :
String
➡Json
(Json에서 payload 항목만 화면에 출력)
| 📄 app.js
// 들어온 메시지(string)를 -> json -> string 으로 변환
function makeMessage(type, payload) {
const msg = {type, payload}
return JSON.stringify(msg)
}
...
function handleSubmit(event) {
event.preventDefault();
const input = messageForm.querySelector("input");
socket.send(makeMessage("new_message", input.value));
input.value = "";
}
function handleNickSubmit(event) {
event.preventDefault();
const input = nickForm.querySelector("input");
socket.send(makeMessage("nickname", input.value));
}
| 📄 server.js
wss.on("connection", (socket) => {
sockets.push(socket);
socket["nickname"] = "anonymous";
console.log("Connected to Browser ✅");
socket.on("close", onSocketClose);
socket.on("message", (msg) => {
const parsed = JSON.parse(msg);
switch (parsed.type) {
case "new_message":
sockets.forEach((aSocket) =>
aSocket.send(
`${socket.nickname} : ${parsed.payload.toString("utf-8")}`
)
);
case "nickname":
socket["nickname"] = parsed.payload; // socket의 닉네임 항목에 사용자 지정 닉네임 설정
}
});
});
728x90
'🏠 Framework > Node.js' 카테고리의 다른 글
[WebRTC] mediasoup로 webRTC SFU 구현하기 (2) | 2022.10.02 |
---|---|
[WebRTC] WebRTC Overview, NAT, STUN (0) | 2022.08.07 |
[Socket.io] WebSocket 개발 환경 세팅 (0) | 2021.10.28 |
[Authentication] OAuth2.0 작동 원리 (feat. Google API) (0) | 2021.09.25 |