Node.js

Node.js socket.io 1:1 1:M 채팅만들기 소켓o (http, socket.io[lib])

svdjcuwg4638 2023. 5. 26. 10:08

저번 글에선 SSE를 이용하여 채팅기능을 만들고 서버에서 일방적으로 실시간 응답을 해줄 수 있다고 했는데

실시간으로 소통할 수 있는 방법이 하나 더 있습니다. 

서버와 유저간 Web Socket을 뚫으면 됩니다.

그럼 양방향으로 실시간 응답이 가능합니다. 

Web Socket은 쌩자바스크립트 문법으로 개발할 수도 있지만

대부분의 상황에선 브라우저간 호환성이 좋은 socket.io 라이브러리를 설치해서 사용합니다.

 

socket.io 설치는 

npm install socket.io

입력하시면 끝입니다.

그리고 우리의 server.js에서 셋팅이 조금 필요합니다.

 

1. 하단과 같은 코드를 const 많이 모여있는 곳 하단에 추가해주시면 됩니다.

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

(복붙하실 때 const app = express() 보다 밑에와야합니다)

 

2. server.js 중간쯤에 보시면 예전에 만들어뒀던 app.listen 이거 코드를 

(이랬던걸)
app.listen(8080, function () {
  console.log('listening on 8080')
});

(이렇게)
http.listen(8080, function () {
  console.log('listening on 8080')
}); 

이렇게 바꾸시길 바랍니다. 

뭘 한거냐면 그냥 간략하게 express를 이용해서 서버를 띄우던걸

http라는 nodejs 기본 라이브러리 + socket.io를 이용해서 띄운겁니다.

 

 

갑자기 http라는게 뭐냐고 물으신다면

https://stackoverflow.com/questions/17696801/express-js-app-listen-vs-server-listen

다음 게시물을 참고하시면 되겠습니다.

(실은 우리는 현재 http라는걸 이용해서 서버를 띄우고 있습니다. express라는 라이브러리는 http라는 라이브러리를 쉽게 사용하기 위한 도구일 뿐입니다)

아무튼 소켓을 뚫을 수 있는 서버로 업그레이드 한거지 과거에 만들었던 서버와 동작방식은 차이가 없습니다.

 

채팅할 수 있는 페이지를 하나 만들어줍니다.

socket.ejs 파일을 새로 만들어봅시다.

안에 들어갈 내용은 그냥.. index.ejs에 있던거 전부 복붙하면 되겠습니다.

그 다음에 /socket으로 방문하면 socket.ejs를 보여주도록 합시다.

(server.js)

app.get('/socket', function(요청,응답){
  응답.render('socket.ejs')
});

그럼 이제 /socket 으로 접속하면 socket.ejs 보입니까. 전 보입니다.

그리고 여기 HTML 파일에도 socket.io 라이브러리를 설치하셔야합니다.

그래야 쉬운 문법을 이용해서 서버와 채팅을 주고받을 수 있으니까요.

 

 

구글에 socket.io cdn 이라고 검색하시면 cdn 제공해주는 페이지가 몇개 뜰텐데 

https://cdnjs.com/libraries/socket.io (대충 이런 곳들이요)

거기서 socket.io.js 라고 끝나는 파일을 다운받거나 링크를 복사해서 <script>태그로 첨부해주시면 됩니다.

근데 내가 설치한 socket.io 라이브러리와 동일한 버전을 가져오면 되겠습니다.

라이브러리 버전은 여러분들 작업폴더의 package.json 파일에 기록되어있습니다. 

<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.js"></script> 

▲ 그래서 저는 이런 코드를 chat.ejs에 복붙했습니다. 끝! 

(이거 따라치시면 안됩니다 여러분의 package.json에 써있는 버전과 동일한거 찾으셔야함)

 

웹소켓 연결하는 법

socket.ejs 파일에 진짜 채팅 기능개발을 해보도록 합시다.

<script>태그로 socket.io 설치한 곳 밑에 <script>태그를 또 열어서 다음과 같이 작성합니다.

(chat.ejs) 

<script src="jQuery 설치한곳"></script>
<script src="socket.io 설치한곳"></script>

<script>
  var socket = io();
</script>

▲ 그냥 한줄 쓰시면 이제 웹소켓을 이용해 서버와 실시간 소통채널을 개설한겁니다.

서버도 누군가 웹소켓으로 접속한걸 캐치해주고 싶으면 

 

(server.js)

io.on('connection', function(){
  console.log('연결되었어요');
});

▲ 어떤놈이 웹소켓으로 서버에 connection 했을 때 콘솔창에 뭐 출력하라는 소리입니다.

그럼 이제 /socket 페이지를 방문할 때마다 자동으로 웹소켓으로 서버와 연결해줍니다.

연결이 될 때마다 서버는 콘솔창에 뭔가 출력해주고요.

 

유저가 서버에게 데이터 보내는 법 

유저가 서버에 간단한 메세지를 보내고 싶으시면

socket.emit() 이라는 간단한 코드 한줄이면 됩니다.

버튼을 누르면 유저 -> 서버에게 메세지를 전달해봅시다. 

(chat.ejs) 

<script src="jQuery 설치한곳"></script>
<script src="socket.io 설치한곳"></script>

<button id="send">서버로 데이터 보내기</button>

<script>
  var socket = io();
  $('#send').click(function(){
    socket.emit('user-send', '안녕하쇼')
  });
</script>

▲ emit() 안에는 파라미터가 두개 필요한데, 왼쪽은 이벤트 명을 작명하시면 되고 오른쪽은 전달할 데이터 적어주시면 됩니다.

그럼 서버는 'user-send' 라는 이벤트명으로 보낸 '안녕하쇼'라는 데이터를 수신할 수 있습니다.

 

유저가 보낸 데이터를 서버가 수신하는 법은 

(server.js)

io.on('connection', function(socket){
  console.log('연결되었어요');
  
  socket.on('user-send', function(data){
    console.log(data)
  });
  
});

▲ 이벤트리스너랑 비슷한 문법을 씁니다.

'user-send' 라는 이벤트가 발생하면 console.log(data) 라는걸 실행해주세요~라는 코드입니다.

socket.on을 쓰면 되는데 socket.on은 콜백함수 파라미터를 function(socket) 이렇게 하나 넣어주시면 사용가능합니다.

data라는 파라미터엔 유저가 보낸 글이 들어있습니다. 그니까 '안녕하쇼'라는 문자가 들어있겠네요.

진짜 수신하는지 확인하고 싶으면 빨리 전송버튼 눌러보십시오.

 

서버가 유저에게 메세지 보내는 법 

서버가 유저들에게 메세지를 보내고 싶으면 

io.emit('작명', '보낼메세지'); 

이렇게 쓰면 됩니다.

그럼 모든 유저에게 메세지를 보낼 수 있습니다.

모든 유저에게 보내는걸 일명 "broadcast 한다"고 합니다.

 

유저는 서버의 메세지를 수신하고 싶으면 

그니까 서버가 io.emit() 한걸 수신하고 싶으면 이벤트리스너가 필요합니다.

(socket.ejs)

<script>
  var socket = io();
  socket.on('작명', function(data){
    console.log(data)
  })

</script>

항상 모든 웹소켓 메세지들은 이벤트리스너로 수신할 수 있습니다.

 

그럼 단체 채팅방 만들고 싶으면 

이렇게 코드를 짜면 되지않을까요. 

(server.js)

io.on('connection', function (socket) {

  socket.on('user-send', function (data) {
    io.emit('broadcast', data)  //모든사람에게 데이터 전송
  });
 
});

아무튼 위와같이 코드 짜면 무슨 일이 일어날까요?

1. user-send 이벤트가 일어나면 (유저가 메세지를 보내면)

2. 모든 참여자에게 io.emit('broadcast', 유저가보낸메세지) 해줍니다. 

서버가 모든 사람에게 메세지를 뿌려주는 확성기 역할을 해주겠군요. 

이게 단체 채팅방의 작동방식 아니겠습니까. 

 

(chat.ejs) 

<script>
  var socket = io();
  $('#send').click(function(){
    socket.emit('user-send', '안녕하쇼')
  });

  socket.on('broadcast', function(data) {
      $('#content').append('<div>' + data + '</div>')
  });
</script>

▲ 유저는 socket.on 어쩌구라는 이벤트리스너를 장착해놓으면

서버가 io.emit()으로 보낼 때마다 그 데이터를 수신가능합니다. 

그리고 유저는 'broadcast' 이름의 데이터가 도착하면 html로 만들어줍니다.

 

그리고 이 정도 코드만 짜놓으면 유저간 자유롭게 채팅을 나눌 수 있는 서비스가 완성된 것입니다.

 

socket으로 메세지 보낼 땐 id와 header 정보도 전달됩니다

io.on('connection', function(socket){
  console.log(socket);
}); 

서버에서 socket이라는 파라미터를 출력해보면

지금 접속한 유저의 header 정보, 유니크한 socket용 id 이런 것들이 출력됩니다. 

특히 socket.id 하면 유저의 유니크한 id를 출력해볼 수 있는데

이걸 이용해서 내가 원하는 사람에게만 메세지를 보내거나 할 수도 있습니다.

 

io.on('connection', function(socket){
  io.to(socket.id).emit("broadcast", '서버응답임');
}); 

io.to(소켓아이디).emit()

이러면 원하는 소켓id를 가진 사람에게만 메세지를 보낼 수 있습니다.

 

하위 채팅방 만드는 법 

하위 채팅방을 만들어서 거기 들어있는 사람끼리만 채팅을 할 수 있게 만들 수도 있습니다.

서버가 유저를 채팅방에 쏙 집어넣어주면 되는데 

socket.join("room1");

이런 코드를 짜면 room1 이라는 채팅방에 유저를 넣어줄 수 있습니다. 

채팅방은 미리 만들 필요 없고 그냥 이름 작명하면 알아서 만들어줍니다.

 

1. 그럼 유저가 room1에 접속하고 싶으면 서버에게 요청을 하고

2. 서버는 그럼 요청받으면 room1에 집어넣어주면 채팅방 완성이겠네요 

요청도 GET POST 이런게 아니라 그냥 socket으로 합니다.

(socket.ejs)

<button id="room1">채팅방1 입장</button>
<button id="room1-send">채팅방1에 메세지 전송</button>

<script>
  $('#room1').click(function(){
    socket.emit('joinroom', '제발');
  });

  $('#room1-send').click(function(){
    socket.emit('room1-send', '어쩌구저쩌구' )
  });
  
</script>

1. 유저는 채팅방1 입장버튼 누르면 room1에 입장시켜달라고 떼를 썼고

그럼 서버는 입장시켜주도록 코드짭니다.

2. 그리고 채팅방1 전송버튼 누르면 어쩌구저쩌구라고 메세지를 보냅니다.

 

(server.js)

io.on('connection', function(socket){

  socket.on('joinroom', function(data){
    socket.join("room1");
  });

  socket.on('room1-send', function(data){
    io.to("room1").emit('broadcast', data);
  });
});

1. 서버는 떼쓰는 요청을 받으면 room1에 넣어주면 되고 

2. room1-send라는 이름의 요청을 받으면 room1에 있는 사람들에만 broadcast 해주면 됩니다.

io.to('룸이름').emit()

이렇게 쓰면 원하는 룸의 사람들에게만 broadcast 가능합니다.

 

깃허브 자료

https://github.com/svdjcuwg4638/learnNode/tree/40d8a64ada67df9b9b0411a43a9db42bc1e7d6a5/nodeSocket/appleNode

 

GitHub - svdjcuwg4638/learnNode

Contribute to svdjcuwg4638/learnNode development by creating an account on GitHub.

github.com