간단한 예제를 만든다.
먼저, socket.io는 각 client에서 라이브러리를 로딩해주는 socket.io의 client, 그리고 서버를 구성하는 socket.io가 있다.
var server = http.createServer(app);
const io = require('socket.io')(server);
// connection이라는 이벤트가 발생하면 유저 연결이라는 신호를 주고, 아래 2개의 이벤트가 발생하면 callbak해줌.
// chat message라는 이벤트가 발생하면 io에서 msg를 emit하고
// disconnect라는 이벤트가 발생하면 유저의 연결을 끊어 줌.
io.on('connection', (socket) => {
console.log("a user connected");
socket.on("chat message", (msg) => {
console.log("chat message : ", msg);
io.emit("chat message", msg);
});
socket.on('disconnect', () => {
console.log("a user disconnected");
});
});
서버는 위와 같이 http에서 만든 서버의 변수 이름을 socket.io의 값 안에 넣어준다. 그러면 socket.io는 해당 서버에서 통신하게 되는 것이다. 그리고 io.on()이라는 method를 사용했는데, 이 method는 딱 보면 connection이라는 이벤트를 받았을 때 a user connected라는 값을 출력해 주는 것 같다. 그리고 이에 대한 callback으로 socket.on에서 chat message, disconnect라는 event가 있으면 이에 대한 값을 다뤄주는 일종의 event handler인 것 같다. socket.on에서 chat message를 받으면 이 메시지를 출력해 주고 io.emit으로 chat message라는 event를 발생시키는 것 같고, disconnect라는 event를 받으면 a user disconnect라는 log를 출력해 주는 것 같다.
잘 모르겠는 건, io와 socket의 차이인데, app.js에서 io라는 것의 callback으로 socket이라는 인자를 받았는데, 음... 아직 잘 모르겠다.
다음, namespace와 room의 개념이 있다. namespace는 전체 채팅방, room은 각 채팅방의 개념으로 이해하면 될 것 같다. 서버에서는 io.of()를 이용해 namespace를 지정하고, client는 namespace만 지정해 주면 된다.
const io = require(‘socket.io’)(server);
...
// NameSpace 1번
const namespace1 = io.of(‘/namespace1’);
// connection을 받으면, news 이벤트에 hello 객체를 담아 보낸다
namespace1.on(‘connection’, (socket) => {
namespace1.emit(‘news’, { hello: “Someone connected at namespace1” });
});
이런 식으로 io.of를 이용해서 namespace를 지정하고, namespace 또한 socket의 일종이기 때문에 이를 이용해 namespace1에서는 namespace2의 내용이 보이지 않게 만들 수 있다.
또, namespace 내부에는 room이라는 것이 있다. 이 room이 채팅방이라고 생각하면 편할 것 같은데, 일단 내 프로젝트는 1개의 namespace, 그리고 여러개의 room을 둘 예정이다. room은 socket.join()으로 접속하고, socket.leave()로 나간다. 특정 room에게 이벤트를 보낼 때는 room.to()를 이용해서 보낸다.
결국 내가 구현하는 백엔드에서는 각 이벤트들을 정의하고, 이 이벤트들을 어떻게 다룰지만 만들어 주면 되는 것 같다.
메시지를 보내는 것은 프론트이다. 프론트에서 emit 등을 이용해 메시지, 또는 event를 emit하면 서버에서 해당 event를 받아와서 어떻게 다룰지 정해주는 것 같다.
io.on('connection', (socket) => {
console.log("a user connected");
socket.on('disconnect', () => {
console.log("a user disconnected");
});
//socket에서 leaveroom이라는 이벤트를 받으면
socket.on("leaveRoom", (num, name) => {
// socket에서 누군가가 방을 나갔다고 말해주고
socket.leave(room[num], () => {
console.log(name + ' leave room ' + room[num]);
// io에서 room에게 leaveRoom이라는 이벤트를 보낸다.
io.to(room[num]).emit('leaveRoom', num, name);
});
});
// socket에서 joinRoom이라는 이벤트를 받으면
socket.on("joinRoom", (num, name) => {
// socket에서 room으로 join시켜주고
socket.join(room[num], ()=>{
console.log(name + ' join room '+ room[num]);
// io에서 room에게 joinRoom이라는 이벤트를 보낸다.
io.to(room[num]).emit('joinRoom', num, name);
});
})
socket.on("chat message", (num, name, msg) => {
console.log("방 번호 : ", num, "chat message : ", msg);
io.to(room[num]).emit("chat message : ", name, msg);
});
});
블로그 글을 참고해서 프론트(웹 사이트)를 만들었고, 해당 웹 사이트에서 서버에 접속하면 user connected가 나온다. 이후 만약 서버를 종료하면 disconnect가 log로 출력된다.
방에 join하면 front에서 joinRoom이라는 event를 발생시키고 socket.join을 이용해서 해당 user를 room에 넣어준다. 이후 해당 room에게 joinRoom이라는 이벤트를 발생시키면 그 이벤트를 front에서 받아 새 유저가 접속했다는 것을 알려준다.
방에 leave하는 것도 동일하다. front에서 leaveRoom이라는 event를 발생시키고 socket.leave를 이용해 user를 room에서 빼 준다. 이후 해당 room에세 io.to().emit()을 이용해 이벤트가 발생했다고 말해주면 그 이벤트를 front에서 받아 유저가 나갔다고 말해준다.
채팅도 동일하다. 만약 front에서 chat message라는 이벤트가 발생하면 서버에서는 해당 room, name, msg를 받아서 log에 출력해 주고, io.to().emit()을 이용해서 해당 룸에게 어떤 사람이 뭐라고 보냈는지 이벤트를 발생시킨다.
그럼 내가 고민해봐야 할 것은, 음...
1. 한 client가 여러 개의 room에 들어가고 나올 수 있는가?
- join을 이용해 room에 접속할 수 있다.
- 접속 시 DB에서 해당 user가 방에 없으면 접속하게 만들고, 퇴장 시 DB에서 해당 user가 있을 때만 퇴장하게 만들자.
2. 한 client가 여러 개의 room에서 각각 다른 메시지를 받을 수 있는가?
- io.to(특정 room).emit()을 이용해 특정 room에만 event를 전달할 수 있다.
- 해당 room에 어떤 사람이 있는지는 검사할 필요가 없다. 이미 front에서 user가 특정 room에 접속하기 때문.
3. 어떻게 방에 접속하고 나오고 메시지를 보낼 것인가?
- GET /join/:room
- GET /exit/:room
- POST /send/:room
- 이런 식으로 url을 이용해 특정 방에 접근/퇴장/메시지 작성
을 할 수 있을 것 같다.
'Development > Socket.io' 카테고리의 다른 글
[Socket.io] Socket.io를 이용한 실시간 채팅 (0) | 2022.11.01 |
---|---|
[Socket.io] 채팅 기능에 관한 고찰 (0) | 2022.06.24 |