2022.02.14 TIL
웹 소켓(Web Socket)
메시지를 교환하기 위한 통신 방법 중 하나. ws라는 프로토콜을 사용한다.
웹 소켓의 특징 2가지
1. 양방향 통신(Full-Duplex)
- 양방향 통신이랑 데이터 송,수신을 동시에 처리할 수 있는 통신 방법.
2. 실시간 네트워킹(Real-Time Networking)
- 웹 환경에서 채팅, 주식, 비디오 데이터 등의 데이터들은 연속된 데이터를 화면에 빠르게 보여주는 등의 실시간 처리가 필요할 경우 사용 가능하다.
웹 소켓 동작 과정
- Handshaking - 연결 확립
- Socket open - 실시간 데이터 교환
- Socket close - 통신 종료
보안 고려 사항
- Non browser clients
웹 브라우저 클라이언트를 사용할 경우, header의 origin 정보를 확인함으로써 악성 javscript 를 걸러낼 수 있다. 이는, 웹 브라우저에서 기존 사용하던 동일 근원 정책을 통해 악성 리소슬부터 보호할 수 있다는 것.
웹 브라우저가 아닌 환경에서는 동인 근원 정책을 활용할 수 없으므로, 사용에 유의해야 함 - Origin Consideration
웹 브라우저와 마찬가지로 웹 서버에서도 origin을 확인하는 로직이 추가되어야 한다. 알수 없는 출처로부터 요청이 들어온다면,HTTP 403 Forbidden
상태 응답을 줄 것. - WebScoket Client Authentication
웹 소켓 프로토콜은 handshaking 단계에서 서버가 클라이언트를 인증하는 특별한 방법을 제시하지 않는다. 따라서 클라이언트 인증이 필요한 경우, HTTP 인증이나 TLS 인증 등을 사용해야 한다.
Node 서버 웹 소켓 예제
npm i ws cookie-parser dotenv express express-session morgan nunjucks
// app.js
const express = require("express");
const path = require("path");
const morgan = require("morgan");
const cookieParser = require("cookie-parser");
const session = require("express-session");
const nunjucks = require("nunjucks");
const dotenv = require("dotenv");
dotenv.config();
const webSocket = require("./socket");
const indexRouter = require("./routes");
const app = express();
app.set("port", process.env.PORT || 4000);
app.set("view engine", "html");
nunjucks.configure("view", {
express: app,
watch: true,
});
app.use(morgan("dev"));
app.use(express.static(path.join(__dirname, "public")));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser(process.env.COOKIE_SECRET));
app.use(
session({
resave: false,
saveUninitialized: false,
secret: process.env.COOKIE_SECRET,
cookie: {
httpOnly: true,
secure: false,
},
})
);
app.use("/", indexRouter);
app.use((req, res, next) => {
const error = new Error(`${req.method} ${req.url} 라우터가 없습니다.`);
error.status = 404;
next(error);
});
app.use((err, req, res, next) => {
res.locals.message = err.message;
res.locals.error = process.env.NODE_ENV !== "production" ? err : {};
res.status(err.status || 500);
res.render("error");
});
const server = app.listen(app.get("port"), () => {
console.log(app.get("port"), "번 포트에서 대기 중");
});
webSocket(server);
// socket.js
const WebSocket = require("ws");
module.exports = (server) => {
const wss = new WebSocket.Server({ server });
// 웹 소켓 연결 시 실행
wss.on("connection", (ws, req) => {
// 클라이언트의 IP를 알아내는 방법
const ip = req.headers["x-forwarded-for"] || req.connection.remoteAddress;
console.log("새로운 클라이언트 접속", ip);
// 클라이언트로부터 메시지 수신 시
ws.on("message", (message) => {
// 그냥 받으니 버퍼로 옴
console.log(message.toString());
});
// 에러 발생 시
ws.on("error", (err) => {
console.log(err);
});
//연결 종료 시
ws.on("close", () => {
console.log("클라이너트 접속 해제", ip);
// setInterval 안 지우면 메모리 누수 발생
clearInterval(ws.interval);
});
// 3초마다 클라이언트로 메시지 전송
ws.interval = setInterval(() => {
/*
웹 소켓에는 4가지 상태가 있다.
CONNECTION(연결 중), OPEN(열림), CLOSIN(닫는 중), CLOSED(닫힘)
*/
if (ws.readyState === ws.OPEN)
ws.send("서버에서 클라이언트로 메시지를 보냅니다.");
}, 3000);
});
};
// views/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" />
<script defer>
const webSocket = new WebSocket("ws://localhost:4000");
webSocket.onopen = () => {
console.log("서버와 웹 소켓 연결 성공");
};
webSocket.onmessage = (e) => {
console.log(e);
webSocket.send("클라이언트에서 서버로 답장을 보냅니다.");
};
</script>
<title>GIF 채팅방</title>
</head>
<body>
<div class="">F12를 눌러 console 탭과 network 탭을 확인하세요.</div>
</body>
</html>
client-side Socket.IO 사용시 404
<script src="/socket.io/socket.io.js"></script>
<script>
const socket = io.connect("http://localhost:4000", {
path: "/socket.io",
});
socket.on("news", (data) => {
console.log(data);
socket.emit("reply", "Hello Node.JS");
});
</script>
테스트 당시 index.html 을 Live Server로 켜 놓고 브라우저 콘솔을 키니 아래와 같dㅣ /socket.io/socket.io.js 파일이 없다는 오류가 떴다.
이거 때문에 1시간을 고민하고 있었는데, Url 포트 번호가 내가 설정한 것과 다르다는 것을 뒤늦게 깨달았다....;;;
브라우저에서 localhost:port 로 접속해야 하는 것을 Live Server로 테스트 하니 이 모양이 나지 멍청아
참고자료
https://caileb.tistory.com/185
Author And Source
이 문제에 관하여(2022.02.14 TIL), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@goatyeonje/2022.02.14-TIL저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)