웹 소켓을 편리하게 사용할 수 있도록 도와주는 라이브러리이다. 웹 소켓을 지원하지 않는 IE9와 같은 브라우저에서는 알아서 웹 소켓 대신 폴링 방식을 사용하여 실시간 데이터 전송을 가능하게 한다. 클라이언트 측에서 웹 소켓 연결이 끊겼다면 자동으로 재연결을 시도하고, 채팅방을 쉽게 구현할 수 있도록 메서드를 준비해두었다.
웹 소켓으로 구현하려는 서비스가 좀 더 복잡해진다면 Socket.IO를 사용하는 것이 편하다. Socket.IO가 할 수 있는 일을 ws 패키지가 못한다는 뜻은 아니다. Socket.IO에 편의 기능이 많이 추가되어 있다는 뜻...
npm i socket.io
const SocketIO = require('socket.io');
module.exports = (server) => {
const io = SocketIO(server, {path: './socket.js'});
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('클라이언트 접속 해제', ip, socket.id);
clearInterval(socket.interval);
});
socket.on('error', (error) => { //에러 시
console.error('socket.io Error : ', error);
});
socket.on('reply', (data) => { //클라이언트로부터 메시지 수신 시
console.log('클라이언트로부터 받은 메시지 : ', data);
});
socket.interval = setInterval(() => { //3초마다 클라이언트로 메시지 전송
socket.emit('news', 'Hello Socket.IO!!');
}, 3000);
})
}
socket.io 패키지를 불러와 익스프레스 서버와 연결한다. SocketIO 객체의 두 번째 인수로 옵션 객체를 넣어 서버에 관한 여러 가지 설정을 할 수 있다. 위 소스에서는 클라이언트가 접속할 경로인 path 옵션만 적용했다. 클라이언트에서도 이 경로와 일치하는 path를 넣어야 한다.
연결 후에는 이벤트 리스너를 붙인다. connection 이벤트 : 클라이언트가 접속했을 때 발생하고, 콜백으로 소켓 객체(socket)를 제공한다. io와 socket 객체가 Socket.IO의 핵심이다. socket.request 속성으로 요청 객체에 접근할 수 있다. socekt.request.res로는 응답 객체에 접근할 수 있다. 또한 socket.id로 소켓 고유의 아이디를 가져올 수 있다. 이걸로 소켓의 주인이 누구인지 특정할 수 있다.
socket에도 이벤트 리스너를 붙인다. disconnect : 클라이언트가 연결을 끊었을 때 발생 error : 통신 과정에서 에러가 나왔을 때 발생 reply : 사용자가 직접 만든 이벤트? 클라이언트에서 reply라는 이벤트명으로 데이터를 보낼 때 서버에서 받는 부분이다.
이렇게 이벤트명을 사용하는 것이 ws 모듈과는 다르다.
아래 emit 메서드로 3초마다 클라이언트 한 명에게 메시지를 보내는 부분이 있는데, 인수가 두 개이다. 첫 번째 인수는 이벤트 이름 두 번째 인수는 데이터 위 소스로 이야기한다면 news라는 이벤트 이름으로 Hello Socket.IO!! 라는 데이터를 클라이언트에 보낸 것이다. 클라이언트가 이 메시지를 받기 위해서는 news 이벤트 리스너를 만들어두어야 한다.
ws와는 다르게 http 프로토콜을 사용한다. path 옵션은 서버와 클라이언트가 일치해야 통신이 가능하다.
<!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">
<title>Socket.IO 테스트</title>
</head>
<body>
<script src="/socket.io/socket.io.js"></script>
<script>
const socket = io.connect('<http://localhost:8081>', {
path: '/socket.io'
});
socket.on('news', (data) => {
console.log('socket.io로부터 받은 메시지 : ', data);
socket.emit('reply', 'Hello socket.io??');
})
</script>
dd
</body>
</html>
Socket.IO는 먼저 폴링 방식으로 서버와 연결한다. 그래서 코드에서 HTTP 프로토콜을 사용한 것이다. 폴링 연결 후, 웹 소켓을 사용할 수 있다면 웹 소켓으로 업그레이드한다. 웹 소켓을 지원하지 않는 브라우저는 폴링 방식으로, 웹 소켓을 지원하는 브라우저는 웹 소켓 방식으로 사용 가능한 것이다.
처음부터 웹 소켓만 사용하고 싶다면, 클라이언트에서 다음과 같이 옵션을 줄 수 있다.
<!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">
<title>Socket.IO 테스트</title>
</head>
<body>
<script src="/socket.io/socket.io.js"></script>
<script>
const socket = io.connect('<http://localhost:8081>', {
path: '/socket.io',
transports: ['websocket']
});
socket.on('news', (data) => {
console.log('socket.io로부터 받은 메시지 : ', data);
socket.emit('reply', 'Hello socket.io??');
})
</script>
dd
</body>
</html>
<script src="/socket.io/socket.io.js"></script> 는 Socket.IO에서 클라이언트로 제공하는 스크립트이며, 실제 파일이 아니다. 이 스크립트를 통해 서버와 유사한 API로 웹 소켓 통신이 가능하다. 스크립트가 제공하는 io 객체에 서버 주소를 적어 연결한다.