본문 바로가기

Node.js

Node.js Socket Programming (3)

이번 챕터에서는 Node.js에서 WebSocket서버와 클라이언트 구현 방법에 대해 소개합니다. WebSocket은  TCP 기반의 실시간 통신 프로토콜로  Request and Response모델인 HTTP와 달리 지속적인 연결을 통해 클라이언트와 서버 간의 대화식 통신을 가능하게 합니다. WebSocket이 널리 사용되면서 기존에 웹에서 비효율적인 실시간 통신이 데스크탑 어플리케이션 수준으로 높아지게 되었습니다.

WebSocket은 웹 브라우저와 웹 서버에서 구현되도록 설계되었지만 클라이언트와 서버 간의 실시간 통신이 필요한 모든 응용 프로그램 및 모바일 웹과 모바일 어플리케이션에까지 많이 사용하는 추세입니다. 채팅 응용 프로그램, 온라인 게임 및 금융 거래 플랫폼과 같이 실시간 업데이트 또는 실시간 데이터 스트리밍이 필요한 응용 프로그램에서 자주 사용됩니다.

Node.js에서 Websocket을 사용하려면 External Library를 설치해야 합니다. 별도의 Built-in 모듈이 없을 정도로 안정적인 기능을 제공하는 라이브러리들이 있습니다. 가장 많이 사용하는것이 ws 패키지 입니다. 

 

새로 디렉토리를 생성하고 해당 디렉퇴리에서 npm으로 ws패키지를 설치합니다.

 

npm install ws

 

WebSocket기반 에코서버를 만들어 볼것입니다. 아래 코드를 작성합니다.

 

const WebSocket = require('ws');

// Create a WebSocket server
const wss = new WebSocket.Server({ port: 8080 });

// Handle new connections
wss.on('connection', (ws) => {
  console.log('New client connected');

  // Handle incoming messages
  ws.on('message', (message) => {
    console.log(`Received message: ${message}`);

    // Send the message back to the client
    ws.send(message.toString());
  });

  // Handle disconnections
  ws.on('close', () => {
    console.log('Client disconnected');
  });
})

<ws-server.js>

 

코드는 실로 간단합니다. 8080번 포트로 websocket서버를 생성하고 접속을 기다리면 됩니다. 클라이언트에서 데이터가 수신되면 'message' 리스너가 호출되고 해당 메시지를 String변환하여 반향합니다. (message는 Buffer Class객체임으로 그대로 보내면 바이너리로 인식됩니다.)

 

테스트는 PostMan을 사용합니다. 

 

 

Create New를 하여 새로운 콜렉션을 추가해야 합니다.  WebSocket Request를 선택후 확인버튼을 누릅니다. 베타버전이지만 테스트에는 문제 없습니다.

 

 

Raw포맷을 선택합니다. Socket.io도 지원되는데 다음 챕터에서 소개할것입니다. URL을 입력합니다. http형식과 동일하며 ws로 시작합니다.  

Message 란에 원하는 메시지를 적은후에 Connect 버튼을 클릭합니다. 서버에 접속이 되면  Send를 눌러 메시지를 전송합니다.

 

하단에 Messages항목에 주고 받은 데이터를 확인할 수 있습니다. 

 

Websocket클라이언트를 별도 개발할 필요가 없다면 PostMan으로 테스트하는것은 서버를 사전검증하기 위한 좋은 선택이 됩니다.  하지만 클라이언트는 브라우저임으로 간단히 작성해서 시험해보는 것도 좋습니다. 이제 Websocket Client를 제작해 보도록 하겠습니다. 아래와 같이 html페이지를 작성합니다.

 

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>WebSocket Example</title>
  </head>
  <body>
    <script>
      // Create a WebSocket connection
      const ws = new WebSocket('ws://localhost:8080');

      // Handle the connection event
      ws.addEventListener('open', () => {
        console.log('Connected to server');

        // Send a message to the server
        ws.send('Hello, server!');
      });

      // Handle incoming messages
      ws.addEventListener('message', (event) => {
        console.log(`Received message: ${event.data}`);
      });

      // Handle disconnections
      ws.addEventListener('close', () => {
        console.log('Disconnected from server');
      });
    </script>
  </body>
</html>

<wsclient.html>

 

위 파일을 브라우져에서 열어봅니다. 서버 콘솔창에서는 아래와 같이 출력될 것입니다.

 

 

New client connected
Received message: Hello, server!

 

서버는 단말에서 수신된 데이터를 그대로 반향하기 때문에 브라우져에도 동일한 데이터가 전달이 되었을 것입니다. 브라우져에서 개발자 콘솔을 개방하면 (크롬의 경우 F12를 누릅니다.) 아래 그림과 같이 수신된 데이터를 확인할 수 있습니다.

 

 

Node.js에서 간단한 WebSocket 연동에 대해서 소개드렸습니다. 예제를 보면 간단하지만 실제 필드에 적용시 고려해야 할 점이 많습니다. 개발자는 아래의 예외적인 상황에 대처해야 합니다.

 

재접속 : 클라이언트는 네트워크 오류나 서버 프로세스재기동등의 원인으로 접속이 언제든지 종료될 수 있다는 사실을 인지하고 있어야 합니다. 사용자가 명시적으로 더 이상 사용하지 않겠다는 액션을 하기전 까지 시스템에서의 연결 종료를 항상 캐치하여 자동으로 재연결을 시도해야 합니다.

 

연결시간 만료 : 일부 브라우져는 포커싱을 잃거나 일정시간 데이터 송수신이 없을 경우 자동으로 WebSocket 연결을 종료합니다. 일정 간격으로 Ping, Pong을 보내거나 별도의 프로토콜을 정의하여 송수신함으로써 연결세션을 유지해 주어야 합니다.

 

패킷 파편화 문제 : WebSocket은 결국 TCP/IP기반의 프로토콜임으로 패킷의 파편화 현상이 발생합니다. TLV프로토콜을 설계하여 파편화된 패킷이 수신되는 경우를 대비하여야 합니다.

 

비정상 패킷 : 개발자의 실수 또는 의도적인 버퍼런을 노린 해커등의 의해 사전에 정의되지 않는 패킷이 수신되는 경우가 있습니다. 전혀 대비하지 않을 경우 결과를 예측할 수 없을 것이기에 수신된 패킷은 처리전 반드시 패킷 검증 절차를 거쳐야 합니다.

 

이와 같은 예외상황에 대처하는 코드를 작성하는 것은 간단하지 않습니다. 만약에 비지니스 로직에 Socket.IO같은 훌륭한 라이브러리를 사용할 수 있다면  제가 언급했던 문제를을 신경쓰지 않아도 됩니다. 다음 챕터에서는 Socket.IO에 대해 소개하도록 하겠습니다.

 

읽어주셔서 감사합니다.

 

 

'Node.js' 카테고리의 다른 글

Node.js Socket Programming (4)  (0) 2023.02.28
Node.js Socket Programming (2)  (0) 2023.02.21
Node.js Socket Programming (1)  (0) 2023.02.18
Node.js로 Restful API Server 만들기(5)  (1) 2023.02.16
Node.js로 Restful API Server 만들기(4)  (0) 2023.02.15