Socket

gogigogigogi·2025년 2월 3일

websocket


웹소켓(서버측, 클라이언트측)에서 전송할 수 있는 데이터 타입은 문자열과 바이너리 데이터 뿐이다. 따라서 다른 타입의 데이터를 보낼때는 JSON.stringify()로 직렬화하고 데이터를 받을 때는 JSON.parse()로 역직렬화해서 처리한다.

client 설정

  • 기본 내장 모듈인 WebSocket을 사용한다. (웹소켓은 HTML5 표준 기술로 기본적으로 제공된다.)
  • WebSocket으로 웹소켓 객체를 생성한다.
      const socket = new WebSocket('ws://localhost:8080');
  • WebSocket 이벤트 종류
    • open : 웹소켓이 성공적으로 열렸을 때
    • message : 웹소켓으로 데이터를 주고 받을 때
    • error : 웹소켓 연결 중 오류가 발생했을 때
    • close : 웹소켓 연결이 종료되었을 때
  • 사용 예시
    • addEventListener 또는 onopen, onmessage 등의 방식도 사용할 수 있다.
socket.addEventListener('open', (e) => {
  console.log('서버 연결 완료');
  // console.log(e);
  // socket.send('채팅방 입장'); // 서버에게 메세지를 보냄
});

socket.addEventListener('message', (e) => {
        console.log('서버로부터 받은 메세지', e.data);
      });
  • 소켓을 통한 데이터 전송
socket.send(JSON.stringify(보낼 데이터));

server 설정

  • npm install ws로 라이브러리 설치
  • ws 모듈로 웹소켓을 생성하고 이벤트를 처리한다.
  • ws 모듈 이벤트 종류
    • connection: 클라이언트와 웹소켓 서버가 연결되었을 떄
    • message: 클라이언트에게 메세지를 받았을 때
    • error: 연결 중 오류
    • close: 클라이언트와 연결 종료
  • 사용 예시
const ws = require('ws');

const server = app.listen(PORT, () => {
  console.log(`http://localhost:${PORT}`);
});

const wsServer = new ws.Server({ server });

wsServer.on('connection', (socket, req) => {
  // console.log(socket); // 연결된 하나의 클라이언트에 대한 정보
  const clientId = generateUniqueId();
  sockets.push(socket); // 접속한 클라이언트 socket을 배열에 추가

  socket.on('message', (message) => {
    console.log(`${clientId} ${message}`); 
    // 연결된 모든 클라이언트에게 보내는 것
    sockets.forEach((client) => {
      client.send(`${message}`);
    });
  });

서버측에서 데이터를 받을 때 버퍼객체로 받게 되는데, toString()으로 문자열로 변경할 수 있다. 또한 템플릿 리터럴로 처리하면 toString()을 암시적으로 호출해서 변환한다.

socket io


client 설정

  • <script src="/socket.io/socket.io.js"></script>로 socket.io를 사용할 수 있다.

    /socket.io/socket.io.js url 요청만으로 사용할 수 있는 이유는?
    백엔드에서 socket 서버가 동작하면 자동으로 해당 경로에서 클라이언트 라이브러리를 제공하기 때문이다.

  • const socket = io()로 클라이언트 소켓 생성과 서버 소켓 연결을 한다.

  • 기본 이벤트 종류

    • connect : 클라이언트가 서버에 연결 성공했을때 발생
    socket.on('connect', () => {
      console.log('Connected to server');
    });
    • disconnect : 클라이언트가 서버와의 연결을 끊을 때 발생
    socket.on('disconnect', () => {
      console.log('Disconnected from server');
    });
    • error : 일반적인 모든 오류가 있을 때 발생
    socket.on('error', (err) => {
      console.error('An error occurred:', err);
    });
    • connect_error : 연결 중 오류가 있을 때 발생
    socket.on('connect_error', (err) => {
      console.error('Connection error:', err);
    });
    • reconnect : 클라이언트가 서버에 다시 연결될 때 발생
    socket.on('reconnect', (attemptNumber) => {
      console.log('Reconnected to server after', attemptNumber, 'attempts');
    });

server 설정

  • npm install socket.io로 라이브러리 설치
  • 기본 이벤트 종류

    • connection : 서버 소켓에 연결한 클라이언트가 있을 때 발생
    io.on('connection', (socket) => {
      console.log('A user connected');
    });
    
    • disconnect : 기존 연결된 클라이언트의 연결이 끊어졌을 때 발생
    socket.on('disconnect', () => {
      console.log('Disconnected from server!');
    });
    • disconnectiong : 연결이 완전히 끊어지기 직전에 발생
    socket.on('disconnecting', () => {
      console.log('User is disconnecting');
      // 자원 정리나 상태 저장 등의 작업 수행
    });
    • error : 연결 중 오류가 있을때 발생
    socket.on('error', (err) => {
      console.error('Error occurred:', err);
    });

사용자 지정 이벤트

  • 사용자가 커스텀 이벤트이름을 만들어서 클라이언트 - 서버 간 동일한 이벤트 이름을 사용해서 소켓 통신을 할 수 있다.

  • 사용 예시

    emit()을 사용하는 쪽에서 인자에 사용할 데이터 외에, 함수를 보내게 된다면
    서버측에서 이 함수를 실행하는것은, 서버측에서 함수자체를 실행하는것이 아니라 클라이언트측에서 해당 함수를 실행하라는 트리거를 보내는 것이다.

  • 이벤트를 보내는 쪽 (emit)

    socket.emit(
      'event_name',
      'hello',
      10,
      { name: 'allie' },
      (res1, res2, res3) => {
        console.log(res1);
        console.log(res2);
        console.log(res3);
      }
    );
  • 이벤트를 받는 쪽 (on)

    socket.on('event_name', (arg1, arg2, arg3, cb) => {
      console.log('[event_name]:: ', arg1, arg2, arg3);
      cb(arg1, arg2, arg3);
    });

room

  • room 이란 socket.io에서 여러 클라이언트(소켓)이 참여하고 떠날 수 있는 채널을 의미한다.
  • room 서버에서 사용하고 관리하는 개념이다.
  • room 관련 api
    • join :

      socket.join('room1', () => {
        console.log('Joined room1');
      });
    • leave :

      socket.leave('room1', () => {
        console.log('Left room1');
      });
    • to, in : 해당 방에 있는 모든 클라이언트에게 메세지를 보낸다.
      (to와 in은 같은 기능을 한다)

      io.to('room1').emit('event_name', 'This message is for room1');
    • clients : 해당 방에 있는 모든 클라이언트의 소켓 정보를 가져온다.

      io.in('room1').clients((error, clients) => {
        if (error) throw error;
        console.log('Clients in room1:', clients);
      });
    • adapter.rooms : 현재 존재하는 모든 방과 각 방의 포함된 클라이언트 정보를 가져온다.

      console.log('All rooms:', io.sockets.adapter.rooms
                  ```
    • broadcast : 현재 클라이언트(소켓)을 제외한 나머지에게 메세지를 보낸다.

      socket.on('sendMessage', (message) => {
        socket.broadcast.emit('message', message);
      });

      특정 클라이언트(소켓)에만 메세지를 보낼때는

      socket.on('sendMessageToSpecificClient', (targetSocketId, message) => {
      io.to(targetSocketId).emit('message', message);

    io 와 socket 객체 사용

  • io 객체 - 서버 전체와 관련된 작업 처리
    • 전체 클라이언트에게 메세지 보내기
    • 특정 방에 있는 전체 클라이언트에게 메세지 보내기
  • socket 객체 - 특정, 개별 클라이언트와의 연결 작업 처리
    • 특정 클라이언트에게 메세지 보내기
    • room에 특정 클라이언트를 추가
    • room에서 특정 클라이언트를 제거
    • 현재 클라이언트를 제외한 모든 클라이언트에게 메세지 보내기

서버와 마찬가지로 클라이언트에서도 socket.id로 고유의 소켓id를 확인할 수 있다.
(서버가 가지고 있는 socket.id와 동일한 값)

http 모듈과 express 모듈 사용

  • http 모듈을 사용한 서버 생성과 실행 예시

    const server = http.createServer((req, res) => {
      res.statusCode = 200;
      res.setHeader('Content-Type', 'text/plain');
      res.end('Hello World');
    }));
    
    server.listen(3000, () => {
      console.log('Server is running on port 3000');
    });
  • express 모듈을 사용한 서버 생성과 실행 예시

    const express = require('express');
    const app = express();
    
    app.listen(3000, () => {
      console.log('Server is running on port 3000');
    });
  • http 모듈로 서버를 생성하고 인자로 app을 넣는 예시

    const express = require('express');
    const http = require('http');
    const app = express();
    
    const server = http.createServer(app);
    server.listen(3000, () => {
      console.log('Server is running on port 3000');
    });

express로 생성한 app을 인자로 넣어서 서버를 생성할 수 있는 이유는?
http 모듈로 생성한 서버는 req,res를 인자로 받는 함수를 받는 형태이다. express의 app 또한 req, res를 인자로 받는 함수 형태로 동일하기 때문이다.

app.listen()으로 서버 실행이 가능한 이유는?
내부적으로는 동일하게 http 모듈로 서버를 생성하기 때문이다. (이때 this는 app을 의미)

app.listen = function(){
var server = http.createServer(this);
return server.listen.apply(server, arguments);
};

0개의 댓글