노드 심화_3

·2022년 12월 27일
0

노드 심화

목록 보기
3/9

소켓 연결 코드 분리하기

1) 추상화

; 코드를 이해하기 쉽게 함수로 분리하기

- 추상화 전 코드

io.on('connection', (sock) => {
  console.log('새로운 소켓이 연결됐어요!');

  sock.on('BUY', (data) => {
    const emitData = {
      ...data,
      date: new Date().toISOString(),
    };

    io.emit('BUY_GOODS', emitData);
  });

... // 생략

  sock.on('disconnect', () => {
    console.log(sock.id, '연결이 끊어졌어요!');
  });
});

- 가이드라인

io.on('connection', (sock) => {
  const { watchBuying, watchByebye } = initSocket(sock);

  watchBuying();

  watchByebye();
});
  1. 서버에 소켓이 새로 연결되면,
    (io.on('connection', ~~~~)
  2. 서버에서 소켓 연결할때 필요한 준비를 하고,
    (~~~ = initSocket(sock);)
  3. 구매를 하는지 감시하면서
    (watchBuying();)
  4. 나가는지 감시한다.
    (watchByebye();)

- 추상화 후 코드

// app.js

function initSocket(sock) {
  console.log('새로운 소켓이 연결됐어요!');

  // 특정 이벤트가 전달됐는지 감지할 때 사용될 함수
  function watchEvent(eventName, func) {
    sock.on(eventName, func);
  }

  // 연결된 모든 클라이언트에 데이터를 보낼때 사용될 함수
  function sendMessageAll(eventName, data) {
    io.emit(eventName, data);
  }

  return {
    watchBuying: () => {
      watchEvent('BUY', (data) => {
        const emitData = {
          ...data,
          date: new Date().toISOString(),
        };
        notifyEveryone('BUY_GOODS', emitData);
      });
    },

    watchByebye: () => {
      watchEvent('disconnect', () => {
        console.log(sock.id, '연결이 끊어졌어요!');
      });
    },
  };
}

func는 sock.on에 있던 (data)부터의 전체 함수 부분을 뜻함
sock.on(eventName, func) == sock.on("BUY", (data) => ... )

data는 sock.on에 있던 모든 data 부분을 뜻함
io.emit("BUY_GOODS", emitData) == io.emit(eventName, data)

반환해주기 위해 return을 사용하며, 객체분해구조할당의 경우는 변수명과 실제 return되는 객체의 키 값이 일치해야 한다.
const { watchBuying, watchByebye }
== watchBuying: () => &watchByebye: () =>

이렇게 코드를 읽기 쉽도록 원래 있던 코드를 분리하면서, 새로운 함수를 만들어 나가는 과정을 "추상화"한다고 표현합니다!

이렇게 추상화 된 코드는 보통 역할에 맞는 파일에 묶여서 관리되는데요, 바로 해보겠습니다!

2) 기능의 역할

; 특정 역할을 하는 코드들은 묶어서 파일로 분리!

일단, initSocket 함수와 io.on('connection', ~~~) 처럼 생긴 소켓 연결과 관련된 코드를 따로 분리해볼까요?

차근차근 따라해주세요!

  1. 소켓 관련된 코드만 따로 정리해둘 socket.js 파일 만들기

  2. initSocket 함수와 io.on('connection', ~~~) 처럼 생긴 소켓 연결과 관련된 코드를 **app.js** 파일에서 **socket.js** 파일로 옮기기

  3. initSocket 함수가 const io = socketIo(http); 객체를 필요로 하니 이 코드도 그대로 옮깁니다!
    이 코드에서는 socket.io 모듈을 사용하기 때문에 해당 모듈을 호출하는 const socketIo = require('socket.io') 도 옮깁니다.

  4. const io = socketIo(http);에서 http 객체도 필요하니 **app.js**에서 http 객체를 모듈로 내보내줍니다!
    http 객체를 내보낼때는 **app.js**에서 module.exports = http; 코드를 통해서 내보냅니다.

  5. socket.js 파일에서 **app.js** 파일이 내보내준 http 객체를 가져와서 사용하도록 해줍니다!

  6. app.js를 실행을 해보면, 왼쪽 하단의 socket 메시지가 뜨지 않는 것을 확인할 수 있다.
    socket.js 실행 시 소켓이 연결되었다는 메시지를 확인할 수 있는데, 매번 socket.js을 실행할 수 없으므로 조치를 취해야 한다.

    => server.js 파일을 생성하여 socket.jsapp.js의 기능을 분리해 주어야 한다.

  7. server.js 파일을 생성합니다.

  8. app.js파일에서는 서버를 켜지 않도록 http.listen 코드를 제거한 후, server.js로 이동해준다.

  9. **server.js** 파일에서 **app.js**socket.js 파일을 참조합니다.

const http = require('./app');
require('./socket'); // 이렇게 불러오기만 해도 소켓에 연결이 됩니다.
  1. 참조만 하면 안되겠죠? 참조한 http 객체를 가지고 서버를 켜주세요!
http.listen(8080, () => {
  console.log('서버가 요청을 받을 준비가 됐어요');
});

이제 server.js 파일을 실행해야만 서버가 켜지며, 서버가 켜질때는 항상 소켓까지 연결 준비가 완료된 상태가 되었습니다!!

최종

- socket.js

const socketIo = require('socket.io'); // 1. 모듈 불러오기
const http = require('./app');

const io = socketIo(http); // 3. http 객체를 Socket.io 모듈에 넘겨서 소켓 핸들러 생성

// 4. 소켓 연결 이벤트 핸들링
io.on('connection', (sock) => {
  const { watchBuying, watchByeBye } = initSocket(sock);

  watchBuying();

  watchByeBye();
});

function initSocket(sock) {
  console.log('새로운 소켓이 연결되었어요!');

  // sock.on을 대신해서, 어떤 역할을 하는지 추상화 한 함수
  function watchEvent(eventName, func) {
    sock.on(eventName, func);
  }

  // 현재 접속한 모든 클라이언트 들에게 메시지를 전송하는 구나 라고 이해할 수 있는 함수
  function sendMessageAll(eventName, data) {
    io.emit(eventName, data);
  }

  return {
    watchBuying: () => {
      watchEvent('BUY', (data) => {
        const emitData = {
          nickname: data.nickname, // 서버가 보내준 구매자 닉네임
          goodsId: data.goodsId, // 서버가 보내준 상품 데이터 고유 ID
          goodsName: data.goodsName, //서버가 보내준 구매자가 구매한 상품 이름
          date: new Date().toISOString(), //서버가 보내준 구매 일시
        };

        sendMessageAll('BUY_GOODS', emitData);
      });
    },
    watchByeBye: () => {
      watchEvent('discount', () => {
        console.log(sock.id, '연결이 끊어졌어요!');
      });
    },
  };
}

- app.js

// app.js

module.exports = http;

- server.js

const http = require("./app");
require("./socket");

// 5. app 대신 http 객체로 서버 열기
http.listen(8080, () => {
    console.log('서버가 요청을 받을 준비가 됐어요!');
  });
profile
개발자가 되는 과정

0개의 댓글