2022. 2. 12. 17:52ㆍ프로젝트/Just Site
이번에 회사에서 소켓 통신을 한다고 해서 한번 찍먹해보기로 했다.
그동안 서버파트를 오지게 기피했는데, 생각보다 단순해서 놀랐다.
Socket.io란?
Socket.io는 웹소켓을 활용해 만든 라이브러리다.
실시간, 양방향 통신을 지원해준다. (서버 <=> 클라이언트)
이것만 기억하자
구조는 생각보다 간단한데, 캐치볼을 생각하면 된다.
양쪽 다 야구글로브를 끼고 있고, 공은 양쪽에게 무한정 있다.
그리고 받은 공을 색깔에 맞게 분류하는 거다.
던지는 건 'emit', 받는 건 'on'이라고 기억하고 진행해보자.
튜토리얼 시작하기
오늘은 socket.io 공식 홈페이지의 튜토리얼과 함께한다.
설명이 부족한거 같으면 사이트에 들어가서 추가로 확인해보자.
기본 파일 생성
다음의 순서대로 진행한다.
1. 폴더를 생성
2. npm 초기화
3. index.js 생성
4. index.html 생성
1. 폴더를 생성
파일 탐색기에서 새 폴더를 만들거나,
mkdir 키워드로 폴더를 만들자.
mkidr <폴더 이름>
ex) mkdir socket-chat-example
cd socket-chat-example
2. npm 초기화
npm init으로 패키지 정보를 생성한다.
npm init
// package.json
{
"name": "socket-chat-example",
"version": "0.0.1",
"description": "my first socket.io app",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {}
}
3. index.js 생성
서버 역할을 하는 파일이다.
// index.js
const express = require('express');
const app = express();
const http = require('http');
const server = http.createServer(app);
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html');
});
server.listen(3000, () => {
console.log('listening on *:3000');
});
- express는 웹 서버 프레임워크다.
- app.get구절은 '/'경로의 요청에 대하여 '/index.html' 파일을 보낸다는 뜻이다.
- server.listen 구절은 3000번 포트를 통해 통신을 한다는 뜻이다.
그리고 express 사용을 위해 패키지를 설치해준다.
npm install express@4
4. index.html
브라우저에 표시될 내용이 적힌 파일이다.
<html>
<head>
<title>Socket.IO chat</title>
<style>
body { margin: 0; padding-bottom: 3rem; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; }
#form { background: rgba(0, 0, 0, 0.15); padding: 0.25rem; position: fixed; bottom: 0; left: 0; right: 0; display: flex; height: 3rem; box-sizing: border-box; backdrop-filter: blur(10px); }
#input { border: none; padding: 0 1rem; flex-grow: 1; border-radius: 2rem; margin: 0.25rem; }
#input:focus { outline: none; }
#form > button { background: #333; border: none; padding: 0 1rem; margin: 0.25rem; border-radius: 3px; outline: none; color: #fff; }
#messages { list-style-type: none; margin: 0; padding: 0; }
#messages > li { padding: 0.5rem 1rem; }
#messages > li:nth-child(odd) { background: #efefef; }
</style>
</head>
<body>
<ul id="messages"></ul>
<form id="form" action="">
<input id="input" autocomplete="off" /><button>Send</button>
</form>
</body>
</html>
간단하게 텍스트 입력이 가능한 input과 버튼으로 구성되어있다.
여기까지 완성했다면 모든 파일을 저장하고 cmd로 가서
index.js를 실행하자.
node index.js
실행 후에 브라우저에 들어가서 localhost:3000으로 들어가면 볼 수 있다.
Socket.io 적용하기
우선 socket.io를 프로젝트에 추가해보자.
npm install socket.io
그 다음 index.js를 수정해보자.
const express = require('express');
const app = express();
const http = require('http');
const server = http.createServer(app);
// socket.io
const { Server } = require("socket.io");
const io = new Server(server);
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html');
});
io.on('connection', (socket) => {
console.log('a user connected');
});
server.listen(3000, () => {
console.log('listening on *:3000');
});
기존 http서버 객체('server' 변수)를 이용해 Server 객체를 만들었고,
이 객체 'io'는 우리의 소켓통신을 담당해줄 것이다.
io.on('connection') 구절을 보면,
아까 말했던 'on'이 있다.
'emit'은 던지기, 'on'은 받기.
'connection'이라는 색깔을 가진 공을 브라우저로부터 받았을 때 실행되는 부분이다.
우리가 클라이언트에서 io를 실행하면 연결된다.
클라이언트(html)에서 io 객체 만들기
index.html의 </body> 바로 위에 다음의 코드를 추가하자.
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io();
</script>
추가한 전체 코드는 다음과 같다.
// index.html
<html>
<head>
<title>Socket.IO chat</title>
<style>
body { margin: 0; padding-bottom: 3rem; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; }
#form { background: rgba(0, 0, 0, 0.15); padding: 0.25rem; position: fixed; bottom: 0; left: 0; right: 0; display: flex; height: 3rem; box-sizing: border-box; backdrop-filter: blur(10px); }
#input { border: none; padding: 0 1rem; flex-grow: 1; border-radius: 2rem; margin: 0.25rem; }
#input:focus { outline: none; }
#form > button { background: #333; border: none; padding: 0 1rem; margin: 0.25rem; border-radius: 3px; outline: none; color: #fff; }
#messages { list-style-type: none; margin: 0; padding: 0; }
#messages > li { padding: 0.5rem 1rem; }
#messages > li:nth-child(odd) { background: #efefef; }
</style>
</head>
<body>
<ul id="messages"></ul>
<form id="form" action="">
<input id="input" autocomplete="off" /><button>Send</button>
</form>
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io();
</script>
</body>
</html>
<script>를 <body>의 맨 마지막에 넣는 이유는 크게는 두가지가 있다.
1. html 요소를 다 불러오지 않은 상태여서 스크립트 동작에 이상이 생길 수 있다. (getElementBy 류)
2. 동작이 더 오래 걸리는 script가 앞에 오면 브라우저에서 html요소가 더 느리게 표시된다.
이제 서버를 재시작 (실행중인 서버를 종료하고 다시 node index.js 실행)
(실행중인 서버 종료: ctrl + c)
하면 localhost:3000에 들어갈 때마다 서버에 'a user connected'가 표시된다.
이는 서버와 클라이언트가 연결이 되었다는 뜻이다.
Emit 하기 (통신 보내기)
이제 브라우저 -> 서버 통신을 해볼 것이다.
index.html의 <script>구절을 수정해보자.
// index.html
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io();
var form = document.getElementById('form');
var input = document.getElementById('input');
form.addEventListener('submit', function(e) {
e.preventDefault();
if (input.value) {
socket.emit('chat message', input.value);
input.value = '';
}
});
</script>
사이트에서 메시지를 작성하고 form이 submit되었을 때,
즉 'send'버튼을 누르면
서버로 input.value (내가 작성한 메시지)를 보내게 된다.
이 때, 'chat message'라는 이벤트로 보내게 되는데,
아까 설명했던 '던진 공의 색깔'이라고 이해하면 된다.
앞으로도 다양한 색깔의 공 (다양한 이벤트)을 던질건데,
받는 쪽에서 공의 색에 따라서 처리하면 된다.
아무튼 우리가 클라이언트에서 'chat message'라는 공을 던졌으니,
서버에서 'chat message'라는 색깔에 대해 처리면 되겠다.
index.js를 수정해보자.
// index.js
...
io.on('connection', (socket) => {
socket.on('chat message', (msg) => {
console.log('message: ' + msg);
});
});
...
기존 io.on('connecton') 구절에 추가해도 좋고,
기존 구절 아래에 이 코드를 통째로 추가해도 좋다.
이제 브라우저에서 메시지를 입력하고 보내면
서버에서 'message: ~' 로그가 출력될 것이다.
서버 -> 클라이언트로 Emit하기
이제 한 클라이언트로부터 메시지를 받았으니,
서버는 다른 클라이언트들한테 받은 메시지를 전달해 줄 것이다.
근데 여기서 생각해 봐야 할 건,
클라이언트는 서버 한명한테만 보내지만
서버는 클라이언트 여러명한테 보낸다.
그렇기 때문에 특정한 클라이언트를 제외하고 보낼수도 있지만,
이 예제에서는 모든 클라이언트에게 전송해보자.
index.js를 수정하자.
io.on('connection', (socket) => {
socket.on('chat message', (msg) => {
io.emit('chat message', msg);
});
});
받은 msg를 'emit'했다.
그럼 이제 클라이언트에서도 공을 받을 준비를 해야한다.
index.html을 수정해보자.
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io();
var messages = document.getElementById('messages');
var form = document.getElementById('form');
var input = document.getElementById('input');
form.addEventListener('submit', function(e) {
e.preventDefault();
if (input.value) {
socket.emit('chat message', input.value);
input.value = '';
}
});
socket.on('chat message', function(msg) {
var item = document.createElement('li');
item.textContent = msg;
messages.appendChild(item);
window.scrollTo(0, document.body.scrollHeight);
});
</script>
socket.on. 즉 메시지를 받으면
<li> 객체를 생성하여 받은 메시지를 넣는다.
이제 서버를 재시작해서
채팅을 치면 다른 창에서도 뜰 것이다.
튜토리얼은 여기까지지만,
Homework 부분이 있어서
다음 게시물에서는 이 숙제를 풀어볼 것이다.
'프로젝트 > Just Site' 카테고리의 다른 글
[Just Site] 9. 살며시 내려오는 애니메이션 만들기 (CSS) (0) | 2022.02.20 |
---|---|
[Just Site] 8. socket.io 공부 (2) - 튜토리얼 숙제 풀이 (0) | 2022.02.12 |
[Just Site] 6. MYSQL과 서버 연결하기 (feat. Network) (0) | 2022.02.09 |
[Just Site] 5. React에서 node.js로 요청보내기 (0) | 2022.02.06 |
[Just Site] 4. React 프로젝트 생성 (Feat. Docker) (0) | 2022.02.06 |