→
Socket.IO
는 웹 소켓 연결을 통해 클라이언트와 서버간에 실시간 양방향 통신을 가능하게하는 JavaScript 라이브러리입니다.
Socket.IO는 클라이언트와 서버 간의 실시간 통신을 위한 사용하기 쉬운 인터페이스를 제공하므로 실시간 업데이트 또는 양방향 통신이 필요한 응용 프로그램을 구축하는 데 널리 사용됩니다. 우리 서비스에서는 실시간 주문과 배달 현황 구축을 위해 사용될 예정입니다.
→ Socket.IO에서 여러가지 개념들을 다루지만, 학습한 내용 중 주요 개념들을 이해한 것이 기반하여 정리하고자 합니다.
1)
Socket
: 소켓은 클라이언트와 서버 간의 연결을 나타냅니다. 소켓을 사용하여 실시간으로 데이터를 보내고 받을 수 있습니다.
2)Server
: 서버는 클라이언트와의 소켓 연결을 설정하고 관리합니다. 서버는 클라이언트로 이벤트를 방출하거나 클라이언트로부터 이벤트를 수신 할 수 있습니다.
3)Client
: 클라이언트는 서버와의 소켓 연결을 설정하고 관리합니다. 클라이언트는 서버와 동일하게, 서버로 이벤트를 방출하거나 서버에서 이벤트를 수신 할 수 있습니다.
1)
Event
: 이벤트는 소켓 연결을 통해 클라이언트와 서버간에 전송 된 메시지입니다. 이벤트 이름은 서버와 클라이언트에서 동일하게 선언하여야 합니다. (JSON, 문자열, 이진 등 모든 형식의 데이터 포함 가능)
2)Namespace
: 네임 스페이스는 클라이언트와 서버 간의 별도의 통신 채널입니다. 단일 서버에서 여러 네임 스페이스를 작성할 수 있으며 클라이언트는 특정 네임 스페이스에 연결하여 해당 네임 스페이스의 다른 클라이언트에게만 이벤트를 수신하거나 방출 할 수 있습니다.
3)Room
: 룸은 함께 결합 된 소켓 그룹입니다. 소켓은 여러 룸에 합류하거나 떠날 수 있습니다. 룸은 연결된 모든 고객에게 방송하는 대신 특정 클라이언트 그룹에 메시지를 보내는 데 유용합니다.
1)
Public
: Public은 연결된 모든 클라이언트에게 메시지가 전송되는 경우입니다. Socket.IO에서 io.emit 연결된 모든 클라이언트에게 메시지를 브로드 캐스트하는 방법으로, 채팅 메시지와 같은 일반 메시지를 연결된 모든 클라이언트에게 보내는 데 유용합니다.// 서버 측 io.on('connection', (socket) => { socket.on('chat message', (msg) => { io.emit('chat message', msg); // 연결된 모든 클라이언트에게 메시지 통신(브로드 캐스트) }); }); // 클라이언트 측 socket.on('chat message', (msg) => { console.log(`Received message: ${msg}`); });
2)
Private
: Private은 특정 고객에게 메시지를 보낼 때입니다. Socket.IO에서 socket.emit 특정 클라이언트에게 메시지를 보내는 방법으로, 알림 또는 알림과 같은 개인 메시지를 특정 클라이언트로 보내는 데 유용합니다.// 서버 측 io.on('connection', (socket) => { socket.on('send notification', (msg, recipientId) => { io.to(recipientId).emit('notification', msg); // 지정된 수신자에게 메시지 보내기 }); }); // 클라이언트 측 socket.on('notification', (msg) => { console.log(`Received notification: ${msg}`); });
3)
Broadcasting
: Broadcasting은 발신자를 제외한 모든 클라이언트에게 메시지가 전송되는 경우입니다. Socket.IO에서 socket.broadcast.emit 발신자를 제외한 모든 연결된 클라이언트에게 메시지를 브로드 캐스트하는 방법으로, 발신자를 제외한 모든 연결된 클라이언트에 사용자 조인 또는 종료와 같은 알림을 보내는 데 유용합니다.// 서버 측 io.on('connection', (socket) => { socket.on('user join', (username) => { socket.broadcast.emit('new user', username); // 발신자를 제외한 연결된 모든 클라이언트에게 메시지 통신(브로드 캐스트) }); }); // 클라이언트 측 socket.on('new user', (username) => { console.log(`New user joined: ${username}`); });
→ 이 경우에는 Private
을 사용해야 한다고 생각합니다.
배달 정보를 특정 운전자에게 보내려고 하며, 연결된 모든 클라이언트 또는 발신자를 제외한 모든 클라이언트가 아니기 때문입니다.
드라이버가 배달 앱에 로그인하면 고유 식별자(드라이버 ID 또는 사용자 이름)을 사용하여 배달 정보가 포함 된 메시지를 보냅니다. socket.emit 방법으로 특정 드라이버만 메시지를 수신하고 연결된 모든 클라이언트는 수신하지 않습니다.
// 서버 측
io.on('connection', (socket) => {
socket.on('driver login', (driverId) => {
const deliveries = getDeliveriesForDriver(driverId);
// 특정 드라이버에 대한 배달 받기
socket.emit('deliveries', deliveries);
// 특정 드라이버에게 배송을 보내기
});
});
// 클라이언트 측
socket.on('deliveries', (deliveries) => {
console.log(`Received deliveries: ${deliveries}`);
});
1)
Emit
: 클라이언트에서 서버로 또는 서버에서 클라이언트로 이벤트를 보내는 데 사용. 이벤트 이름과 보낼 데이터라는 두 가지 이상의 인수가 필요합니다.//첫 번째 인수는 이벤트 이름, 두 번째 인수는 전송될 데이터 socket.emit('chat message', 'Hello, world!');
2)
To
: 특정 소켓이나 방에 이벤트를 방출하는 데 사용. 이벤트가 전송 될 소켓 ID 또는 방 이름이라는 하나의 인수가 필요합니다.// to 메소드는 이벤트를 보낼 소켓 ID를 지정하는 데 사용 io.to('12345').emit('chat message', 'Hello, world!');
3)
On
: 클라이언트 또는 서버에서 이벤트에 대한 리스너를 등록하는 데 사용. 이벤트 이름과 이벤트를 처리하기 위한 콜백 함수라는 두 가지 이상의 인수가 필요합니다.//첫 번째 인수는 이벤트 이름, 두 번째 인수는 이벤트가 수신 될 때 호출되는 콜백 함수(데이터) socket.on('chat message', (message) => { console.log(`Received message: ${message}`); });
4)
Of
: 자체 소켓 및 이벤트 세트로 새 네임 스페이스를 만드는 데 사용. 네임 스페이스의 이름이라는 하나의 인수가 필요합니다.// of 메소드는 새로운 네임 스페이스를 만드는 데 사용 const chatNamespace = io.of('/chat');
→ Socket.IO는 클라이언트와 서버간에 WebSocket 연결을 설정하여 작동합니다.
서버는 들어오는 연결을 확인하고 클라이언트가 방출하는 이벤트를 처리합니다. 클라이언트는 서버에 연결하고 이벤트를 방출하거나 이벤트를 확인할 수 있습니다. 클라이언트가 이벤트를 방출하면 서버는 이벤트를 수신하여 클라이언트로 응답을 다시 보내거나 동일한 네임 스페이스 또는 방에 있는 다른 클라이언트로 이벤트를 브로드 캐스트 할 수 있습니다.
→ Socket.IO의 주요 기능 중 하나는 많은 수의 연결 및 이벤트를 동시에 처리 할 수 있다는 것입니다. 그러나 제대로 관리하지 않으면 성능 문제가 발생할 수 있습니다.
성능 문제를 피하는 한 가지 방법은 setTimeout
과 Socket.IO
와 함께 작동하는 것입니다.
setTimeout 지정된 시간이 지난 후에 기능을 실행할 수있는 내장 JavaScript 기능으로, Socket.IO에서 setTimeout 이벤트를 받은 후 클라이언트에게 승인을 보내는 등 특정 기능의 실행을 지연시키면 서버에 너무 많은 이벤트가 동시에 과부하되는 것을 방지 할 수 있습니다.
// 서버 측
socket.on('message', (data, callback) => {
// 처리 수행
setTimeout(() => {
callback('success');
}, 1000); // 확인을 보내기 전에 1초간 기다리기
});
// 클라이언트 측
socket.emit('message', data, (response) => {
console.log(response); // 1초 후 '성공' 로그 기록
});
npm install socket.io-client
// 서버 측
io.on("connection", (socket) => {
console.log(socket.id); // x8WIv7-mJelg7on_ALbx
});
// 클라이언트 측
socket.on("connect", () => {
console.log(socket.id); // x8WIv7-mJelg7on_ALbx
});
socket.on("disconnect", () => {
console.log(socket.id); // undefined
});
socket.on("connect", () => {
console.log(socket.connected); // true
});
socket.on("disconnect", () => {
console.log(socket.connected); // false
});
//1. connect
// BAD
socket.on("connect", () => {
socket.on("data", () => { /* ... */ });
});
// GOOD
socket.on("connect", () => {
// ...
});
socket.on("data", () => { /* ... */ });
//2. connect_error
// either by directly modifying the `auth` attribute
//주어진 지연
socket.on("connect_error", () => {
socket.auth.token = "abcd";
socket.connect();
});
// or if the `auth` attribute is a function
// 수동으로 다시 연결 필요
const socket = io({
auth: (cb) => {
cb(localStorage.getItem("token"));
}
});
socket.on("connect_error", () => {
setTimeout(() => {
socket.connect();
}, 1000);
});
//3. disconnect
//연결이 끊어지면 다시 시작
socket.on("disconnect", (reason) => {
// ...
});