12. 웹 소켓으로 실시간 데이터 전송하기

진영민·2022년 9월 11일
0

Node.js 교과서

목록 보기
11/13

해당 글은 Node.js 교과서의 내용을 요약, 정리한 글입니다.

웹 소켓이란?

socket.io는 웹 소켓을 활용한 라이브러리일 뿐이며 웹 소켓은 아니다.

웹 소켓은 HTML5에 새로 추가된 스펙으로, 실시간 양방향 데이터 전송을 위한 기술이다.
WS프로토콜을 사용한다.

웹 소켓이 나오기 이전에는 polling을 사용했다.
폴링이란 주기적으로 서버에 업데이트가 있는지 요청을 보낸 후, 있다면 새로운 내용을 가져오는 방식이다.

HTML5가 나오면서 클라이언트와 서버가 연결된 상태로 있는다. 따라서 따로 요청을 보낼 필요가 없다.

서버에서 클라이언트로 통하는 일방향 기술인 SSE(Server Sent Event)도 등장했다.

ws모듈로 웹 소켓 사용하기

//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||8005);
app.set('view engine','html');

nunjucks.configure('views',{
    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);

기본적인 express 서버이다. 하지만 서버를 변수에 저장해 webSocket 함수에 넣는다.
webSocket 함수에 관한 설명이다.

//socket.js
const WebSocket = require('ws');

module.exports = (server)=>{
    const wss = new WebSocket.Server({server});

    wss.on('connection',(ws,req)=>{
        const ip = req.headers['x-forwarded-for']||req.connection.remoteAddress;
        console.log('새로운 클라이언트 접속',ip);
        ws.on('message',(message)=>{
            console.log(message.toString());
        });
        ws.on('error',(error)=>{
            console.error(error);
        });
        ws.on('close',()=>{
            console.log('클라이언트 접속 해제',ip);
            clearInterval(ws.interval);
        });

        ws.interval = setInterval(()=>{
            if(ws.readyState===ws.OPEN){
                ws.send('서버에서 클라이언트로 메시지를 보냅니다.');
            }
        },3000);
    });
};

server에 웹 소켓을 연결했다.
새로운 클라이언트 접속, 에러, 클라이언트 접속 해제, 3초마다 클라이언트로 보내는 메시지가 구현되어 있다.

// routes/index.js
const express = require('express');

const router = express.Router();

router.get('/',(req,res)=>{
    res.render('index');
})

module.exports = router;

Socket.IO 사용하기

ws 패키지는 간단하게 웹 소켓을 사용하고자 할 때 좋다. 하지만 서비스가 복잡해지면 Socket.IO를 사용하는 것이 편하다.
$npm i socket.io@2

//socket.js
const SocketIO = require('socket.io');

module.exports = (server)=>{
    const io = SocketIO(server,{path:'/socket.io'});

    io.on('connection',(socket)=>{
        const req = socket.request;
        const ip = req.headers['x-forwarded-for']||req.connection.remoteAddress;
        console.log('새로운 클라이언트 접속!',ip,socket.id, req.ip);
        socket.on('disconnect',()=>{
            console.log('클라이언트 접속 해제',id,socket.id);
            clearInterval(socket.interval);
        });
        socket.on('error',(error)=>{
            console.error(error);
        });
        socket.on('reply',(data)=>{
            console.log(data);
        });
        socket.interval = setInterval(()=>{
            socket.emit('news','Hello Socket.IO');
        },3000);
    });
};
//index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>GIF 채팅방</title>
</head>
<body>
    <div>F12를 눌러 console탭과 network 탭을 확인하세요.</div>
    <script src="/socket.io/socket.io.js"></script>
    <script>
        const socket = io.connect('http://localhost:8005',{
            path:'/socket.io',
        });
        socket.on('news',function(data){
                console.log(data);
                socket.emit('reply','Hello Node.JS');
        });
    </script>
</body>
</html>

connection 이벤트는 클라이언트가 접속했을 때 발생하고, 콜백으로 소켓 객체를 제공한다.

socket.request속성으로 요청 객체에 접근할 수 있다.
emit메서드로 3초마다 클라이언트 한 명에게 메시지를 보내는 부분이 있다.

/socket.io/socket.io.js는 Socket.IO에서 클라이언트로 제공하는 스크립트이며, 실제 파일이 아니다.
Socket.IO는 먼저 폴링 방식으로 서버와 연결한다.
폴링 연결 후 웹 소켓을 사용할 수 있다면 웹 소켓으로 업그레이드 한다.

profile
코린이

0개의 댓글