• [detect-port] 사용 가능한 포트 찾기 :: 마이구미
    알아두면 좋은 라이브러리 2022. 1. 4. 22:20
    반응형
    이 글은 사용 가능한 포트 번호를 찾는 라이브러리 detect-port 을 다룬다.
    CRA(create-react-app) 에서는 이미 사용 중인 포트 번호가 아닌 사용 가능한 포트 번호로 서버 실행을 도와준다.
    관련 기능에 대해 어떻게 동작되는지 알아본다.

    조금이나마 도움을 줄 수 있는 라이브러리들을 소개하는 카테고리로 분류된 글이다.
    알아두면 좋은 라이브러리

    detect-port 와 같은 라이브러리는 현재 사용 가능한 포트 번호를 찾아주는 용도로 사용된다.
    우리는 이러한 기능을 필요로 하거나, 이미 자연스럽게 사용하고 있다.

    이 라이브러리를 사용하고 있는 대표적인 예는 CRA(create-react-app) 로 들 수 있다.

    그 외에도 익숙한 곳들에서도 많이 사용하고 있는 README.md 에서 확인할 수 있다.

     

    CRA 에서 devServer 실행시 우리는 포트 번호를 따로 설정하지 않는다.

    자동으로 디폴트 포트(3000)를 기반으로 서버가 실행된다.

    하지만 만약 3000번 포트가 사용중이라면 어떻게 될까?

    이미 사용중인 포트라고 알려주고, 3001번 포트를 사용할 것인지를 묻는다.

     

     

    이처럼 이미 자연스럽게 "사용 가능한 포트를 찾는 기능" 을 경험하고 있다.

    CRA 에서는 이미지처럼 안내해주고 다른 포트를 사용할 수 있는 기능을 제공해준다.

    그렇다면 어떻게 CRA 에서는 이러한 기능을 사용할 수 있는지 알아보자.

     

    choosePort(host: string, defaultPort: number): Promise

    Returns a Promise resolving to either defaultPort or next available port if the user confirms it is okay to do. If the port is taken and the user has refused to use another port, or if the terminal is not interactive and can’t present user with the choice, resolves to null.

     

    이 기능은 README.md 에 친절하게 설명되어있다.

    WebpackDevServerUtils 내부의 choosePort() 가 이 역할을 하고 있다.

    내부 파일을 들어가서 확인해보면, 글의 주제인 detect-port 모듈을 사용하고 있는 것을 볼 수 있다.

     

    detect-port 모듈의 실제 코드는 대략 100 라인정도 된다.

    코드를 보면, 재귀적으로 port 번호를 1씩 늘려서 재귀적으로 서버를 listen 하는 로직을 볼 수 있다.

    즉, 간단하게 현재 포트가 사용중이라면 현재 포트 번호 + 1 에 해당하는 번호로 포트를 열어본다.

    그마저도 사용중이라면 계속 + n 으로 사용 가능한 포트를 찾을때까지 실행하면 된다.

     

    detect-port.js

    function tryListen(port, maxPort, hostname, callback) {
      function handleError() {
        port++;
        if (port >= maxPort) {
          debug('port: %s >= maxPort: %s, give up and use random port', port, maxPort);
          port = 0;
          maxPort = 0;
        }
        tryListen(port, maxPort, hostname, callback);
      }
    
      listen(port, hostname, (err, realPort) => { 
        if (err) {
          return handleError();
        }
    
      } 
      ...   
     }

     

    포트 번호를 하나씩 늘리면서 tryListen() 으로 서버 실행이 가능하는지 체크하게 된다.

    서버는 listen 에 성공한다면, callback 을 실행하게 된다.

    여기서 의미하는 callback 은 CRA 기준에서 보면 다음과 같다.

     

    WebpackDevServerUtils.js

    import detect from 'detect-port-alt';
    
    function choosePort(host, defaultPort) {
      return detect(defaultPort, host).then(
        port =>
          new Promise(resolve => {
            if (port === defaultPort) {
              return resolve(port);
            }
            ...

     

    then 의 콜백 함수가 detect-port.js 에서 listen 성공시 실행되는 콜백을 의미한다.

    detect-port 를 통해 사용 가능한 포트 번호를 찾은 후 콜백 함수를 통해 넘겨받는다.

    넘겨 받은 포트 번호를 통해 CRA 에서 터미널 환경에서 안내해주고 다른 포트로 실행할 것인지를 사용자에게 묻는 것이다.

    위 코드를 이어서 보면 터미널에 노출되는 메시지들에 대한 코드들을 볼 수 있다.

     

    WebpackDevServerUtils.js

    chalk.yellow(
      message +
      `${existingProcess ? ` Probably:\n  ${existingProcess}` : ''}`
    ) + '\n\nWould you like to run the app on another port instead?',

     

     

     

     


     

    실제로 이러한 기능은 개발환경에서 편의성을 위해 많이 요구되는 기능이다.

    개인적으로도 여러 devServer 를 사용하는 경우가 빈번하여 포트가 겹쳐서 서버 실행이 실패하는 일이 빈번했다.

    이를 위해 사용 가능한 포트를 찾아 실패하지 않는 기능이 필요했다.

    같은 목적의 라이브러리로 node-portfinder 를 사용하곤 했다.

     

    import * as express from "express";
    import portfinder from "portfinder";
    
    const app = express();
    
    (async () => {
      const PORT =  await findPort();
    
      app.listen(PORT, () => {
        console.log(`Running app at http://localhost:${PORT}`);
        console.log("Press Ctrl+C to quit.");
      });
    })();
    
    async function findPort(start = 3000) {
      return await portfinder.getPortPromise({
        port: start,
      });
    };

     

     

     

    detect-port.js 파일 내부 주석에 check null => check 0.0.0.0 => check localhost => check current ip 순서로 체크하는 정확한 이유는 이해하지 못해서 다루지 않았다.

    혹시 알고 있다면, 댓글로 설명해주시면 감사하겠다.

     

    반응형

    댓글

Designed by Tistory.