Node.js

node> 채팅기능 만들기 3 (Socket.io)

연습노트 2024. 9. 19. 09:39

웹소켓을 이용해서 서버와 유저가 실시간 양방향 통신하는 법을 알아봅시다. 

웹소켓을 좀쉽게 쓰고 싶으면 socket.io 라이브러리를 쓰면 되겠습니다. 

express와 가장 많이 쓰는 websocket라이브러리인데 웹소켓 관련 간편한 기능들을 제공해줍니다. 

socket.io 설치부터 해보도록 합시다. 

 

 

 

socket.io 설치는

 

1. 터미널 열어서 npm install socket.io@4 입력 하고 

 

 

const { createServer } = require('http')
const { Server } = require('socket.io')
const server = createServer(app)
const io = new Server(server) 

2. 서버파일 상단 쯤에 이런거 추가하고

 

 

app.listen(생략)
server.listen(생략)

3. app.listen 이라고 써있던 코드를 server.listen으로 바꿔주고

 

 

<script src="https://cdn.jsdelivr.net/npm/socket.io@4.7.2/client-dist/socket.io.min.js"></script>
<script>
  const socket = io() 
</script>

4. 웹소켓 사용을 원하는 html 파일에도 이런걸 넣어서 socket.io 라이브러리를 설치해둬야 합니다.

저는 채팅방 상세페이지에 넣어봤음 

const socket = io() 이런 코드를 실행하면 바로 서버로 웹소켓 연결을 해줍니다.

 

 

 

io.on('connection', (socket) => {
  console.log('websocket 연결됨')
})

5. 그럼 서버는 누가 웹소켓 연결시 특정 코드를 실행하고 싶으면 위처럼 작성해두면 됩니다.

진짜 출력되나 채팅방 상세페이지 가서 새로고침 해봅시다.

 

 

 

 

 

유저 -> 서버 메세지 전송은 

 

(chatDetail.ejs)

socket.emit('데이터이름', '데이터')  

유저가 서버로 어떤 데이터를 웹소켓으로 전송하고 싶으면 자바스크립트로 이런 코드 실행합시다.

 

 

(server.js)

io.on('connection',(socket) => {
 
  socket.on('데이터이름', (data) => {
    console.log('유저가 보낸거 : ', data)
  })
 
}) 

서버는 유저가 보낸걸 수신하고 싶으면 

socket.on이라는 이벤트리스너를 달아줘야 합니다. 

유저에게 받은 데이터는 data 파라미터안에 들어있습니다.

진짜 되나 출력해봅시다.

 

 

 

 

 

서버 -> 유저 메세지 전송은 

 

(server.js)

io.emit('작명', '서버가보낸메세지') 

이런 코드 실행하면 웹소켓 연결된 모든 유저에게 메세지를 뿌릴 수 있습니다.

 

 

(chatDetail.ejs)

socket.on('작명', (data) => {
  console.log(data)
})

유저는 서버가 뿌린 메세지를 받고 싶으면

script 태그 안에 이벤트리스너같은거 추가해놓으면 됩니다. 

이러면 유저는 서버가 '작명'이라는 이름으로 보낸 데이터를 수신할 수 있습니다.

서버가 보낸건 data 변수 안에 들어있는데 출력해봅시다.

 

 

 

 

 

 

socket.io의 room 기능

 

그래서 실시간 채팅이 어떤 식으로 이루어지냐면

- 어떤 유저가 서버로 메세지를 보내면 

- 서버는 그 메세지를 모든 유저에게 뿌리기

그게 실시간 채팅기능입니다.

 

근데 문제는 서버에서 메세지를 모든 유저에게 뿌릴 필요는 없고

채팅방에 들어있는 사람끼리만 메세지를 주고받게 만들어야 하지 않겠습니까 

그런것도 다행히 쉽게 만들 수 있는데 

socket io 라이브러리를 이용하면 room이란걸 이용합시다.

 

room은 유저들이 입장할 수 있는 일종의 웹소켓 방입니다.

그리고 특정 room에 있는 유저들에게만 메세지 전송하라고 코드짤 수 있어서 이런 기능 이용하면 됩니다.

 

 

 

 

(server.js)

socket.join('룸이름') 

이러면 유저를 특정 룸에 집어넣을 수 있습니다.

참고로 유저를 룸에 넣는건 안전상 서버만 할 수 있습니다.

 

 

Q. 그러면 유저는 룸에 쪼인하고 싶으면 어떻게 함? 

"룸에 좀 쪼인시켜줘라" 이렇게 서버로 부탁메세지 날리고 서버는 그걸 들어주면 됩니다.

 

 

(chatDetail.ejs)

socket.emit('ask-join', '룸이름') 

예를 들어 유저는 이런 메세지를 서버로 전송하고 

 

 

(server.js)

socket.on('ask-join', async (data) => {
  socket.join(data)
}) 

그럼 서버는 누가 ask-join이라는 이름으로 메세지 보내면

룸에 쪼인시켜주라고 하면 되는겁니다.

 

 

 

Q. 유저가 특정 룸에만 메세지를 보내고 싶으면 어떻게 함?

실은 유저가 특정 룸에 메세지를 보내는 문법은 없습니다.

서버는 가능합니다.

그래서 유저는 서버로 “나 이런 룸에 메세지좀 보내줘” 라고 부탁하면 서버는 들어주면 됩니다.

 

 

(chatDetail.ejs)

socket.emit('message', { msg : '메세지내용', room : '룸이름' }) 

다행히 메세지를 보낼 때 문자 숫자뿐만 아니라 array나 object자료도 보낼 수 있기 때문에 

이런 식으로 요구사항도 함께 보내면 되지 않을까요.

그럼 서버는 message라는 이름으로 메세지를 받으면 

이런 룸에 전송하라는 뜻이니까 부탁 들어주면 됩니다. 

 

 

(server.js)

socket.on('message', async (data) => {
  io.to(data.room).emit('작명', data.msg);
}) 

서버가 특정 룸에만 데이터를 쏴주고 싶으면

io.emit이 아니라 io.to(룸이름).emit() 쓰면 됩니다. 

그래서 이런 문법들을 쓰면 실시간 채팅기능을 잘 구현할 수 있겠군요.

 

 

 

 

 

오늘의 숙제 :

채팅상세페이지에서 실시간 채팅할수있는 기능 다음시간까지 만들어오면 됩니다.

- 누가 채팅상세페이지에 접속하면 서버에서 룸을 하나 만들어주고

- 룸이름은 맘대로 해도 되는데 뭐 채팅방의 document _id 같은걸로 해도 되고

- 그 다음에 유저가 input에 뭔가 적어서 전송버튼을 누르면 그게 서버로 전달되고

- 서버가 그걸 같은 룸에 있는 사람끼리 뿌려주면 그게 실시간 채팅 끝입니다. 

수신한 메세지를 html에 띄우고 싶으면 여러분들이 자바스크립트 코드를 잘 짜서 html을 생성해주면 되는것이고요.

 

 

 

 

 

 

유저 로그인정보 출력도 가능 

 

passport로 로그인 기능 구현했을 경우 

socket.io에서 현재 로그인중인 유저정보 출력이 가능합니다.

 

https://socket.io/how-to/use-with-express-session

이런 가이드 따라하면 socket.request.session 출력시 유저 로그인 정보가 들어있습니다.

그럼 이제 현재 메세지 보내는 유저가 누구인지 확인하고 그럴 수 있는 것임

아마 쿠키를 전송해서 까보는 식으로 동작할텐데

passport 안쓰면 웹소켓 메세지 전송시 쿠키도 전송해서 까보거나 해야합니다.