Socket.IO

본 글은 네이버 부스트캠프 과정에서 학습한 내용의 게시글입니다.


1. 배경지식

1.1. Socket 통신

1.1.1. Socket이란

  • 프로세스가 드넓은 네트워크 세계로 데이터를 내보내거나 혹은 그 세계로부터 데이터를 받기 위한 실제적인 창구 역할을 수행
    • 소켓은 떨어져 있는 두 호스트를 연결해주는 도구로써 인터페이스의 역할을 함
  • 프로세스가 데이터를 보내거나 받기 위해서는 반드시 소켓을 열어서 소켓에 데이터를 써보내거나 소켓으로부터 데이터를 읽어들여야 함
    • 데이터를 주고 받을 수 있는 구조체로 소켓을 통해 데이터 통로가 만들어짐
  • 프로토콜, IP 주소, 포트 넘버로 정의됨
  • 역할에 따라 서버 소켓, 클라이언트 소켓으로 구분

1.1.2. 프로토콜

  • 원래 의미는 외교상의 언어로써 의례나 국가간의 약속을 의미
  • 통신에서는 어떤 시스템이 다른 시스템과 통신을 원활하게 수용하도록 해주는 통신 규약, 약속

1.1.3. IP 주소

  • 전 세계 컴퓨터에 부여된 고유의 식별 주소

1.1.4. 포트

  • 네트워크 상에서 통신하기 위해서 호스트 내부적으로 프로세스가 할당받아야 하는 고유한 숫자
  • 한 호스트 내에서 네트워크 통신을 하고 있는 프로세스를 식별하기 위해 사용되는 값
    • 같은 호스트 내에서 서로 다른 프로세스가 같은 포트 넘버를 가질 수 없음
    • 즉, 같은 컴퓨터 내에서 프로그램을 식별하는 번호

1.2. 소켓 통신의 흐름

1.2.1. 흐름도(Flow Chart)

image

1.2.2. 서버 (Server)

  • 클라이언트 소켓의 연결 요청을 대기하고, 연결 요청이 오면 클라이언트 소켓을 생성하여 통신이 가능하게 함
  1. socket() 함수를 이용하여 소켓 생성
  2. bind() 함수로 ip와 port 번호 설정
  3. listen() 함수로 클라이언트의 점근 요청에 수신 대기열을 만들어 몇 개의 클라이언트를 대기 시킬지 결정
  4. accept() 함수를 사용하여 클라이언트와의 연결을 기다림

1.2.3. 클라이언트(Client)

  • 실제로 데이터 송수신이 일어남
  1. socket() 함수로 가장 먼저 소켓을 염
  2. connect() 함수를 이용하여 통신할 서버의 서정된 ip와 port 번호에 통신을 시도
  3. 통신 시도 시, 서버가 accept 함수를 이용하여 클라이언트의 socket descriptor(파일 또는 소켓을 지칭하기 위해 부여한 숫자)를 반환
  4. 이를 통해 클라이언트와 서버가 서로 read(), write()를 하며 통신 (이 과정을 반복)

1.2.4. 소켓 종류

  1. TCP (스트림)
    • 양방향으로 바이트 스트림을 전송, 연결 지향성
    • 오류 수정, 전송 처리, 흐름제어 보장
    • 송신된 순서에 따라 중복되지 않게 데이터를 수신 → 오버헤드가 발생
    • 소량의 데이터보다 대량의 데이터 전송에 적합 → TCP를 사용
  2. UDP (데이터그램)
    • 비연결형 소켓
    • 데이터의 크기에 제한이 있음
    • 확실하게 전달이 보장되지 않음, 데이터가 손실돼도 오류가 발생하지 않음
    • 실시간 멀티미디어 정보를 처리하기 위해 주로 사용
      • ex) 전화

1.3. HTTP 통신과 Socket 통신 비교

1.3.1. HTTP 통신

  • Client의 요청(Request)이 있을 때만 서버가 응답(Response)하여 해당 정보를 전송하고 곧바로 연결을 종료하는 방식
    • Client가 요청을 보내는 경우에만 Server가 응답하는 단방향 통신
    • Server로부터 응답을 받은 후에는 연결이 바로 종료됨
    • 실시간 연결이 아닌, 필요한 경우에만 Server로 요청을 보내는 상황에 유용
    • 요청을 보내 Server의 응답을 기다리는 어플리케이션의 개발에 주로 사용

1.3.2. Socket 통신

  • Server와 Client가 특정 Port를 통해 실시간으로 양방향 통신을 하는 방식
    • Server와 Client가 계속 연결을 유지하는 양방향 통신
    • server와 Client가 실시간으로 데이터를 주고받는 상황이 필요한 경우에 사용
    • 실시간 동영상 Streaming이나 온라인 게임 등과 같은 경우에 자주 사용

2. WebSocket

2.1. 서론

2.1.1. WebSocket이란

  • Transport protocol의 일종
    • 웹 버전의 TCP 또는 Socket이라고 이해하면 됨
  • 서버와 클라이언트 간에 Socket Connection을 유지해서 언제든 양방향 통신 또는 데이터 전송이 가능하도록 하는 기술
  • Real-time web application 구현을 위해 널리 사용되어지고 있음
    • SNS 어플리케이션, LoL과 같은 멀티플레이어 게임, 구글 Doc, 증권거래, 화상채팅 등

2.1.2. 사용 이유

  • 웹 어플리케이션에서 기존의 서버와 클라이언트 간의 통신은 대부분 HTTP를 통해 이루어졌으며 HTTP는 Request/Response 기반의 Stateless Protocol임
    • 즉, 서버와 클라이언트 간의 Socket connection같은 영구적인 연결이 되어있지 않고 클라이언트 쪽에서 필요할 때 Request를 할때만 서버가 Response하는 방식으로 통신이 진행되는 단방향 통신
      • 이 경우 서버쪽 데이터가 업데이트 되더라도 클라이언트 쪽의 화면은 Refresh하지 않는 한 변경된 데이터가 업데이트되지 않는 문제가 발생함
      • 이러한 문제는 일반적인 웹 어플리케이션에서는 기존의 Long polling이나 Ajax를 사용하여 어느정도 해결이 가능하지만 데이터의 빠른 업데이트가 아주 중요한 요소 중에 하나인 어플리케이션에서는 실시간 업데이트가 아주 중요하기 때문에 Web Socket이 아주 중요한 기술로 사용되고 있음
  • Stateful Protocol이기 때문에 클라이언트와 한 번 연결이 되면 계속 같은 라인을 사용해서 통신하기 때문에 HTTP 사용시 필요없이 발생되는 HTTP와 TCP 연결 트래픽을 피할 수 있음
  • HTTP와 같은 포트(80)를 사용하기 때문에 기업용 어플리케이션에 적용할 대 방화벽은 재설정하지 않아도 됨 image

2.1.3. 작동 원리

  1. HTTP 프로토콜을 통해 서버와 클라이언트 간의 WebSocket 연결
  2. 연결이 정상적으로 이루어진다면 서버와 클라이언트 간에 WebSocket 연결이 이루어지고 일정 시간이 지나면 HTTP 연결은 자동으로 끊어짐

2.1.4. HTTP 통신 방법과 WebSocket의 차이

  • WebSocket 프로토콜은 접속 확립에 HTTP를 사용하지만, 그 후 통신은 WebSocket 독자의 프로토콜로 이루어짐
  • header가 상당히 작아 overhead가 적음
    • 장시간 접속을 전제로 하기 때문에, 접속한 상태라면 클라이언트나 서버로부터 데이터 송신이 가능
  • 데이터의 송신과 수신에 각각 커넥션을 맺을 필요가 없어 하나의 커넥션으로 데이터를 송수신 할 수 있음

3. Socket.io

3.1. 서론

3.1.1. Socket.io란

  • 양방햔 통신을 하기위해 웹소켓 기술을 활용하는 라이브러리
    • Node.js를 위한 강력한 Cross-platform WebSocket API
    • ex) 자바스크립트와 jQuery의 관계
  • node.js의 웹 소켓 구현체 중 일종
  • socket.io가 같은 기능을 구현하더라도 약간 느리지만, 많은 편의성을 제공
    • Java, C++, Python 등 여러 언어들의 라이브러리 또한 지원

3.1.2. WebSocket과 Socket.io 비교

WebSocket

  • HTML5 웹 표준 기술
  • 매우 빠르게 작동하며 통신할 때 아주 적은 데이터를 이용함
  • 이벤트를 단순히 듣고, 보내는 것만 가능함

Socket.io

  • 표준 기술이 아니며, 라이브러리임
  • 소켓 연결 실패 시 fallback을 통해 다른 방식으로 알아서 해당 클라이언트와 연결을 시도함
  • 방 개념을 이용해 일부 클라이언트에게만 데이터를 전송하는 브로드캐스팅이 가능함

3.1.3. Socket.io 장점

ws

  • 기본에 충실한 편

Socket.io

  • 보다 다양한 기능 제공
    • ex) room이라는 기능을 이용해 여러 개의 채팅방을 만들 수 있고 소켓에 연결된 전체 클라이언트에게 broadcast를 보낼 수 있다거나, room 별로 broadcast를 보낼 수 있음
    • 이러한 기능들을 보다 쉽고 직관적으로 제공
  • HTML5 WebSocket은 오래된 브라우저의 경우 지원하지 않는 경우가 있음
    • 브라우저 간 호환이나 이전 버전 호환을 고려할 수 있음
  • socket.io는 채팅방에 특화된 라이브러리
    • 만일 양방향 통신 기술이 필요한데 채팅방이 아닌 다른 서비스를 구현한다고 한다면 socket.io는 맞지 않을수 있음

3.2. 사용

3.2.1. 설치

npm i socket.io

3.2.2. 이벤트 통신

  • 소켓IO 의 메소드의 특징은 클라이언트에서 발생하는 이벤트는 개발자가 임의로 설정할 수 있다는 점
    • 이벤트명은 문자열로 지정
    • 직접 이벤트를 발생시킬 수 있음
// 해당 이벤트를 받고 콜백함수를 실행
socket.on("받을 이벤트 명", (msg) => {});

// 이벤트 명을 지정하고 메세지를 보낸다.
socket.emit("전송할 이벤트 명", msg);

3.2.3. 메시지 수신

// 접속된 모든 클라이언트에게 메시지를 전송한다
io.emit("event_name", msg);

// 메시지를 전송한 클라이언트에게만 메시지를 전송한다
socket.emit("event_name", msg);

// 메시지를 전송한 클라이언트를 제외한 모든 클라이언트에게 메시지를 전송한다
socket.broadcast.emit("event_name", msg);

// 특정 클라이언트에게만 메시지를 전송한다
io.to(id).emit("event_name", data);

3.2.4. 메시지 송신

// 클라이언트와 소켓IO 연결됬는지 안됬는지 이벤트 실행. (채팅방에 누가 입장하였습니다/퇴장하였습니다 )
io.on("connection/disconnection", (socket) => {});

// 클라이언트에서 지정한 이벤트가 emit되면 수신 발생
socket.on("event_name", (data) => {});

3.3. 서버 설정

3.3.1. app 서버 생성

const app = require("express")();
const server = app.listen(8005, () => {});

3.3.2. 소켓IO에 서버 정보 넘겨주고 구동

const SocketIO = require("socket.io");

// 서버 연결, path는 프론트와 일치시켜준다.
const io = SocketIO(server, { path: "/socket.io" });

3.3.3. 소켓 연결 성공 시 이벤트 통신

//* 웹소켓 연결 시
io.on("connection", (socket) => {
  //* 연결 종료 시
  socket.on("disconnect", () => {
    console.log("클라이언트 접속 해제", ip, socket.id);
    clearInterval(socket.interval);
  });

  //* 에러 시
  socket.on("error", (error) => {
    console.error(error);
  });

  //* 클라이언트로부터 메시지 수신
  socket.on("reply", (data) => {
    // reply라는 이벤트로 송신오면 메세지가 data인수에 담김
    console.log(data);
  });

  //* 클라이언트로 메세지 송신
  socket.emit("news", "Hello Socket.IO"); // news라는 이벤트로 문자열을 포함하여 송신
});

3.4. 클라이언트 설정

3.4.1. socket.io 모듈 스크립트 로드

  • socket.io 모듈은 내부적으로 “루트/socket.io” 경로에 socket.io.js 파일을 자동으로 등록해둠
    • 결과적으로 위 코드는 socket.io모듈이 자동으로 생성해둔 http://127.0.0.1:8005/socket.io/socket.io.js 에 접근하여 JS 스크립트를 불러오게 됨
    • JS스크립트에서 소켓IO 객체를 뽑아 클라이언트에서도 소켓 통신을 할수 있게 되는 것
<script src="/socket.io/socket.io.js"></script>

3.4.2. socket.io 객체 생성 및 연결

  • 연결할 서버 경로 및 옵션 설정
    • path 옵션: 이 경로를 통해 각종 통신을 수행하며, node.js상에서 설정한 path와 동일하게 지정해야 함
    • transports 옵션: socket.io는 처음에 polling 연결을 시도하고, 웹소켓이 지원되는 브라우저인 경우, ws통신으로 이행한다.: 처음부터 ws로 통신하고자 할 경우, transports 옵션 값을 [‘websocket’]으로 추가 설정해주면 됨
<!-- 익스프레스 서버와 소켓 서버가 연결이 되면, 소켓IO 서버에서 js파일을 넣어준다 -->
<script src="/socket.io/socket.io.js"></script>
<script>
   // 위의 socket.io.js에서 뽑아 쓴다.
   const socket = io.connect('http://localhost:8005', { // ws:// 를 안쓰고 http를 쓴다
      path: '/socket.io', // 서버 path와 일치시켜준다
      transports: ['websocket']
   });

</script>

3.4.3. 송수신 이벤트 처리 (연결/종료/에러/데이터 수신 등)

<!-- 익스프레스 서버와 소켓 서버가 연결이 되면, 소켓IO 서버에서 js파일을 넣어준다 -->
<script src="/socket.io/socket.io.js"></script>
<script>
   // 위의 socket.io.js에서 뽑아 쓴다.
   const socket = io.connect('http://localhost:8005', { // ws:// 를 안쓰고 http를 쓴다
      path: '/socket.io', // 서버 path와 일치시켜준다
      // transports: ['websocket']
   });

   // 서버로부터 메세지 수신
   socket.on('news', function (data) {
      console.log(data);

      // 서버에게 메세지 송신
      socket.emit('reply', 'Hello Node.JS');
   });
</script>

Reference

소켓 통신

[기본] 소켓(SOCKET)통신 이란?

WebSocket

WebSocket 이란?

Socket.io란

Socket.io에 대해서

[SOCKET] 📚 WS 웹소켓 사용해보기

Socket.io 사용

[SOCKET] 📚 Socket.IO 사용 해보기