지난 시간까지 복습을 마치고 이번주부터 소켓에 대해 배우게 됐다.
TCP는 데이터를 신뢰성있게 전송하기 위한 프로토콜을 말한다.
인터넷상에서 데이터를 주고받기 위한 통신 규약
소켓은 프로세스가 네트워크로 데이터를 내보내거나 데이터를 받기 위한 실제적인 창구역할을 한다.
양방향 소통을 위한 프로토콜
브라우저 환경에서 웹소켓 API를 사용하여 웹소켓 클라이언트를 만들 수 있지만, 서버를 만들려면 별도의 라이브러리나 모듈이 필요하다.
npm install ws
https://www.npmjs.com/package/ws
웹소켓을 이용하여 실시간으로 메시지를 주고 받는 서버와 채팅기능을 만드는 실습이다. 사용자의 이름과 채팅내용을 입력 받아서 서버로 전송하고, 서버에서는 메시지를 전송한 사용자 외에 다른 사용자에게도 메시지를 전송한다.
const express = require("express");
const app = express();
const ws = require("ws");
const PORT = 8000;
app.set("view engine", "ejs");
app.use(express.urlencoded({extended:true}));
app.use(express.json());
app.get('/', (req, res)=>{
res.render("client");
})
const server = app.listen(PORT, ()=>{
console.log(`http://127.0.0.1:${PORT}`);
})
// 웹소켓 서버 접속
const wss = new ws.Server({server});
// 브라우저들을(클라이언트) 담을 변수
const sockets = [];
// socket 변수는 접속한 브라우저
wss.on('connection', (socket)=>{
console.log("클라이언트가 연결되었습니다.");
sockets.push(socket);
// 메시지 이벤트
socket.on('message', (message)=>{
console.log(`클라이언트로부터 받은 메시지: ${message}`);
sockets.forEach(element => {
element.send(`${message}`);
});
})
// 오류 이벤트
socket.on('error', (error)=>{
console.log(`에러가 발생했습니다: ${error}`);
})
// 접속종료 이벤트
socket.on('close', (close)=>{
console.log(`클라이언트와 연결이 종료되었습니다: ${close}`);
})
})
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>클라이언트</title>
</head>
<body>
<form id="chat">
<input type="text" id="name" placeholder="이름"><br />
<input type="text" id="msg" placeholder="메시지"><br />
<button type="submit">전송</button>
</form>
<ul></ul>
<script>
const form = document.getElementById("chat");
const ul = document.querySelector("ul");
// 접속할 주소 입력 (ws://127.0.0.1:8000)
const socket = new WebSocket('ws://127.0.0.1:8000');
// 서버에 연결 요청
socket.addEventListener('open', (event)=>{
// send()는 서버로 메시지를 전송
console.log("서버에 연결되었습니다", event);
})
// 메시지 주고 받음
socket.addEventListener("message", (event)=>{
const evt = JSON.parse(event.data);
const li = document.createElement("li");
li.textContent = evt.name + " : " + evt.msg;
ul.append(li);
})
// 오류처리
socket.addEventListener("error", (event)=>{
console.log(`오류가 발생하였습니다: ${event.error}`);
})
// 종료이벤트
socket.addEventListener("close", (event)=>{
console.log(`서버와 연결이 종료되었습니다: ${event}`);
})
////////////////////////// 폼 이벤트 //////////////////////////
form.addEventListener('submit', (event)=>{
event.preventDefault();
const name = form.querySelector("#name");
const msg = form.querySelector("#msg");
socket.send(JSON.stringify({name:name.value, msg:msg.value}));
msg.value = '';
})
</script>
</body>
</html>
클라이언트에서 서버로 메시지를 전송할 때, 이름이나 채팅내용 단일 값이었으면 그냥 문자열로 보내줘도 됐지만, 이름, 채팅내용을 한번에 보내기 위해 JSON 객체로 만들었다.
하지만 그래도 서버로 전송하면 [object, object]로 출력되기만 할 뿐, 전송한 데이터가 나오지 않았다.
해결방법은 JSON.stringify()를 이용해 JSON객체를 문자열로 변환해 전송하는 방법이었다. JSON.stringify를 이용해 문자열로 변환하고, 서버에서는 그 문자열을 그대로 다시 클라이언트로 전송한다.
마지막으로 클라이언트 socket.addEventListener("message", (event)=>{} 부분에서 메시지를 받을 때, JSON.parse() 메서드를 이용해 문자열을 다시 JSON객체로 변환해 이용할 수 있도록 하였다.
소켓을 이용하면 실시간 통신이 가능하다. 실시간으로 데이터를 주고 받을 수 있으므로, 채팅기능을 구현하기에 적합하다. 소켓에 대한 일부 지식과 웹소켓을 이용하는 실습을 통해 채팅기능을 구현해봄으로써 추후에 이러한 서비스를 만들게 된다면, 오늘 배웠던 내용을 이용하면 좋을 것 같다. 특히 서버로 데이터를 보낼 때, JSON 객체 자체를 보내는 게 아니라 문자열로 변환해 보내야한다는 사실이 새로웠다.