GitHub

[React & node] socketIO 연결 편 (1)

hojun lee · 08/25/2023
커버이미지

서울시 Sesac에서 풀스택 실무프로젝트 과정을 들으며 진행했던 팀 프로젝트 [PocaZ], 아이돌 포토카드 거래 플랫폼에서 구현했던 socket.IO를 이용한 채팅 연결을 상세히 기록해보고자 한다.

Live Demo

PocaZ, 아이돌 포토카드 거래 플랫폼

PocaZ

🧀채팅 서비스 설계

  1. 1:1 채팅만 지원
  2. 웹 앱의 웹뷰 형태로 구현
  3. 트래픽 규모 (DAU 1,000명 이내)
  4. 채팅을 join 하는 경로 2곳
  1. 장터 - detail 에서 채팅으로 연결하기 기존 채팅이 있는 경우 / 기존 채팅이 없는 경우
  2. 채팅리스트에서 기존채팅 연결하기
  1. 채팅 이력 mysql DB 보관

🌲 src 폴더 구조

client

📦 
└─src
  ├─ App.jsx
  ├─ components
  │  ├─ InfoBar.jsx // 대화창의 상태정보
  │  ├─ InputMsg.jsx // 채팅을 발신하는 Input
  │  ├─ Messages.jsx // 채팅 메세지 모음
  │  └─ Msg.tsx // 채팅 메세지 표시 UI
  ├─ pages
  │  ├─ Chat.jsx // 1:1 대화창
  │  └─ ChatMain.jsx // 채팅리스트 목록
  ├─ network
      └─ socket.jsx // socket Class 구현

server

📦 
└─src
  ├─ App.js
  ├─ connection
  │  └─ socket.js // socket Class 구현
  ├─ controller
  │  ├─ chat.js
  │  └─ chatRoom.js
  ├─ router
  │  ├─ chat.js
  │  └─ chatRoom.js

😶‍🌫️ socketIO 연결 만들기

socket 통신은 실시간 통신이다. 그래서 이 통신을 연결시켜주는 것이 중요하다. socket을 계속 연결시켜두면 좋지 않다고 하는데, socketIO는 생각보다 똑똑해서 안쓸 땐 끊어주고 쓸땐 연결 시켜주고 효율적으로 관리하기 때문에 나는 서비스가 실행될 때 연결시켜주고 서비스가 접속이 끝날 때 연결을 해제하는 방식으로 구현했다.

따라서 처음 서비스가 실행될 때, connect 해준다.

//main.jsx
import Socket from "./network/socket";

const baseURL = import.meta.env.VITE_HOST_URL;

const root = ReactDOM.createRoot(document.getElementById("root"));
const socket = new Socket(baseURL);

root.render(<App socket={socket} />);

이번에 소켓을 class로 관리했는데, 소켓을 사용할 때 마다 new 해주는건 부담이므로, 재사용하기 위해 class로 정의하였다. 또한 emit, on, join 등의 socket 메서드 공통으로 관리해주고 setter 함수를 사용해 접속하게 했다.

정답은 당연히 아니고, 프로젝트이기 때문에 적용해본 것이다. 각자의 방식을 연구해보길 바란다. 이렇게 진행하다보니 실제로 구현하는 부분에서는 적지 않은 불편함이 있었는데, 먼저 쉽게 구현해보고 성취감을 얻고 리팩토링하는 방식이 수월 할 것 같다.

// client
// network/socket.js
import { io } from 'socket.io-client';

  constructor(baseURL) {
    this.io = io(baseURL, {
      withCredentials: true,
      path: '/api/socket.io',
    });

클래스가 생성될 때 constructor이 실행되기 때문에 서비스가 실행될 때 백엔드에 baseURL 주소에 connect 신호를 보낼 수 있다.

이 연결해줘의 외침을 누군가는 들어야겠지 그것은 server 일 것이다. 서버도 열리게 되면 바로 요청을 듣도록 설정해놓고, 소켓도 연결되면 알리게 작성하였다.

// server
// app.js
const server = app.listen(+config.host.port, () => {
  console.log(`listening on port ${+config.host.port}`);
  initSocket(server);
});
// server
// connection/socket.js
    class Socket{
    this.io = new Server(server, {
      cors: {
        origin: ['http://localhost:3000'],
        credentials: true,
      },
      path: '/api/socket.io',
    });
    this.io.on('connection', (so: any) => {
      console.log('연결되었다. 나의 첫 socketIO');
    })

    ...
    let socket: any;
    export function initSocket(server: any) {
      if (!socket) {
        socket = new Socket(server);
      }
      return socket;
}

mysql까지 연동하여 socket이 연동된다. 두 개가 뜨는 이유는 연결될때마다 console.log가 뜨게 만들어놨기 때문이다.

아무튼 이렇게하면 socket 통신이 연결된다.

실시간 통신의 기반을 마련한 것이다. 두근🍩