웹소켓(서버측, 클라이언트측)에서 전송할 수 있는 데이터 타입은 문자열과 바이너리 데이터 뿐이다. 따라서 다른 타입의 데이터를 보낼때는 JSON.stringify()로 직렬화하고 데이터를 받을 때는 JSON.parse()로 역직렬화해서 처리한다.
WebSocket을 사용한다. (웹소켓은 HTML5 표준 기술로 기본적으로 제공된다.) const socket = new WebSocket('ws://localhost:8080');
socket.addEventListener('open', (e) => {
console.log('서버 연결 완료');
// console.log(e);
// socket.send('채팅방 입장'); // 서버에게 메세지를 보냄
});
socket.addEventListener('message', (e) => {
console.log('서버로부터 받은 메세지', e.data);
});
socket.send(JSON.stringify(보낼 데이터));
npm install ws로 라이브러리 설치const ws = require('ws');
const server = app.listen(PORT, () => {
console.log(`http://localhost:${PORT}`);
});
const wsServer = new ws.Server({ server });
wsServer.on('connection', (socket, req) => {
// console.log(socket); // 연결된 하나의 클라이언트에 대한 정보
const clientId = generateUniqueId();
sockets.push(socket); // 접속한 클라이언트 socket을 배열에 추가
socket.on('message', (message) => {
console.log(`${clientId} ${message}`);
// 연결된 모든 클라이언트에게 보내는 것
sockets.forEach((client) => {
client.send(`${message}`);
});
});
서버측에서 데이터를 받을 때 버퍼객체로 받게 되는데, toString()으로 문자열로 변경할 수 있다. 또한 템플릿 리터럴로 처리하면 toString()을 암시적으로 호출해서 변환한다.
<script src="/socket.io/socket.io.js"></script>로 socket.io를 사용할 수 있다.
/socket.io/socket.io.js url 요청만으로 사용할 수 있는 이유는?
백엔드에서 socket 서버가 동작하면 자동으로 해당 경로에서 클라이언트 라이브러리를 제공하기 때문이다.
const socket = io()로 클라이언트 소켓 생성과 서버 소켓 연결을 한다.
기본 이벤트 종류
socket.on('connect', () => {
console.log('Connected to server');
});
socket.on('disconnect', () => {
console.log('Disconnected from server');
});
socket.on('error', (err) => {
console.error('An error occurred:', err);
});
socket.on('connect_error', (err) => {
console.error('Connection error:', err);
});
socket.on('reconnect', (attemptNumber) => {
console.log('Reconnected to server after', attemptNumber, 'attempts');
});
npm install socket.io로 라이브러리 설치기본 이벤트 종류
io.on('connection', (socket) => {
console.log('A user connected');
});
socket.on('disconnect', () => {
console.log('Disconnected from server!');
});
socket.on('disconnecting', () => {
console.log('User is disconnecting');
// 자원 정리나 상태 저장 등의 작업 수행
});
socket.on('error', (err) => {
console.error('Error occurred:', err);
});
사용자가 커스텀 이벤트이름을 만들어서 클라이언트 - 서버 간 동일한 이벤트 이름을 사용해서 소켓 통신을 할 수 있다.
사용 예시
emit()을 사용하는 쪽에서 인자에 사용할 데이터 외에, 함수를 보내게 된다면
서버측에서 이 함수를 실행하는것은, 서버측에서 함수자체를 실행하는것이 아니라 클라이언트측에서 해당 함수를 실행하라는 트리거를 보내는 것이다.
이벤트를 보내는 쪽 (emit)
socket.emit(
'event_name',
'hello',
10,
{ name: 'allie' },
(res1, res2, res3) => {
console.log(res1);
console.log(res2);
console.log(res3);
}
);
이벤트를 받는 쪽 (on)
socket.on('event_name', (arg1, arg2, arg3, cb) => {
console.log('[event_name]:: ', arg1, arg2, arg3);
cb(arg1, arg2, arg3);
});
join :
socket.join('room1', () => {
console.log('Joined room1');
});
leave :
socket.leave('room1', () => {
console.log('Left room1');
});
to, in : 해당 방에 있는 모든 클라이언트에게 메세지를 보낸다.
(to와 in은 같은 기능을 한다)
io.to('room1').emit('event_name', 'This message is for room1');
clients : 해당 방에 있는 모든 클라이언트의 소켓 정보를 가져온다.
io.in('room1').clients((error, clients) => {
if (error) throw error;
console.log('Clients in room1:', clients);
});
adapter.rooms : 현재 존재하는 모든 방과 각 방의 포함된 클라이언트 정보를 가져온다.
console.log('All rooms:', io.sockets.adapter.rooms
```
broadcast : 현재 클라이언트(소켓)을 제외한 나머지에게 메세지를 보낸다.
socket.on('sendMessage', (message) => {
socket.broadcast.emit('message', message);
});
특정 클라이언트(소켓)에만 메세지를 보낼때는
socket.on('sendMessageToSpecificClient', (targetSocketId, message) => { io.to(targetSocketId).emit('message', message);
서버와 마찬가지로 클라이언트에서도 socket.id로 고유의 소켓id를 확인할 수 있다.
(서버가 가지고 있는 socket.id와 동일한 값)
http 모듈을 사용한 서버 생성과 실행 예시
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello World');
}));
server.listen(3000, () => {
console.log('Server is running on port 3000');
});
express 모듈을 사용한 서버 생성과 실행 예시
const express = require('express');
const app = express();
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
http 모듈로 서버를 생성하고 인자로 app을 넣는 예시
const express = require('express');
const http = require('http');
const app = express();
const server = http.createServer(app);
server.listen(3000, () => {
console.log('Server is running on port 3000');
});
express로 생성한 app을 인자로 넣어서 서버를 생성할 수 있는 이유는?
http 모듈로 생성한 서버는 req,res를 인자로 받는 함수를 받는 형태이다. express의 app 또한 req, res를 인자로 받는 함수 형태로 동일하기 때문이다.
app.listen()으로 서버 실행이 가능한 이유는?
내부적으로는 동일하게 http 모듈로 서버를 생성하기 때문이다. (이때 this는 app을 의미)app.listen = function(){ var server = http.createServer(this); return server.listen.apply(server, arguments); };