와니🤣·23년 3월의 낮·개발

Node.js 에서 기본 모듈인 Net 을 사용하여 TCP 핑을 보내는 방법입니다.


다른 방법은 아래의 글을 참조하세요.

와니네 블로그 - Node.js 에서 TCP/UDP/ICMP 핑 보내기 (Pingus 모듈 사용)

와니네 블로그 - Node.js 에서 UDP 핑 보내기 (기본 모듈 사용)


TCP 핑 보내기

Node.js 의 기본 모듈 중 하나인 Net 모듈을 사용하여 호스트의 특정 TCP 포트 연결을 확인할 수 있습니다.


1. Net 모듈을 임포트합니다.

import net from 'net';

2. 연결하는 데 사용할 소켓을 하나 만듭니다.

const socket = new net.Socket();

3. 소켓에 이벤트 리스너들을 등록합니다.


3.1. 소켓 연결이 수립되었을 때 'connect' 이벤트가 호출됩니다.

socket.on('connect', () => {
  const ip = socket.remoteAddress;
  console.log(`소켓 연결됨: ${ip}`);
});

3.2. 소켓이 완전히 닫겼을 때 'close' 이벤트가 호출됩니다.

socket.on('close', (error) => {
  console.log(`소켓 연결 종료`);
});

3.3. 소켓 연결 중 오류가 발생하면 'error' 이벤트가 호출됩니다.

socket.on('error', (error) => {
  console.error('소켓 연결 오류:', error);
});

3.4. 설정된 시간동안 소켓 활동이 없으면 'timeout' 이벤트가 호출됩니다.

socket.setTimeout(2000); // 타임아웃 시간 2000ms로 설정
socket.on('timeout', () => {
  console.error('소켓 타임아웃');
});

4. 원하는 호스트와 TCP 포트에 소켓 연결을 시도합니다.

socket.connect(80, 'example.com');

하나의 코드로 만들면 다음과 같습니다. 연결 가능 여부만 확인할 것이므로 타임아웃 이벤트 발생이 소켓을 제거하는 코드가 추가되어 있습니다.

import net from 'net';

const socket = new net.Socket();

// 연결됨
socket.on('connect', () => {
  const ip = socket.remoteAddress;
  console.log(`소켓 연결됨: ${ip}`);
});

// 연결 종료
socket.on('close', (hadError) => {
  console.log(`소켓 연결 종료`);
});

// 오류
socket.on('error', (error) => {
  console.error('소켓 연결 오류:', error);
});

// 타임아웃
socket.setTimeout(2000); // 타임아웃 시간 2000ms로 설정
socket.on('timeout', () => {
  console.error('소켓 타임아웃');
  socket.destroy();
});

socket.connect(80, 'example.com');


실행하면 연결이 수립된 뒤 아무 활동이 없으므로 타임아웃이 발생하고 연결이 종료됩니다.

// 콘솔 출력 결과
소켓 연결됨: 93.184.216.34
소켓 타임아웃
소켓 연결 종료

연결할 수 없는 호스트의 경우 연결이 수립되지 않고 타임아웃이 발생한 뒤 연결이 종료됩니다.

socket.connect(80, '10.1.2.3');

// 콘솔 출력 결과
소켓 타임아웃
소켓 연결 종료


알 수 없는 호스트이거나 연결 중 오류가 발생하였을 경우 'error' 이벤트가 발생한 뒤 연결이 종료됩니다.

socket.connect(80, 'notexisthost.notexist');

// 콘솔 출력 결과
소켓 연결 오류: Error: getaddrinfo ENOTFOUND notexisthost.notexist
    at GetAddrInfoReqWrap.onlookup [as oncomplete] (node:dns:109:26) {
  errno: -3008,
  code: 'ENOTFOUND',
  syscall: 'getaddrinfo',
  hostname: 'notexisthost.notexist'
}
소켓 연결 종료

사용하기 쉽게 하나의 함수로 만들면 다음과 같습니다.

import net from 'net';

function tcping(host, port = 80) {
  const socket = new net.Socket();
  let isConnected = false; // 연결 수립 여부 확인용
  let ip = null;
  let error = null;

  return new Promise((resolve, reject) => {
    // 연결됨
    socket.on('connect', () => {
      isConnected = true; // 연결 수립됨
      ip = socket.remoteAddress; // 연결된 호스트의 IP
    });

    // 연결 종료
    socket.on('close', (hadErr) => {
      if (error) {
        reject(error);
      } else {
        resolve(ip);
      }
    });

    // 오류
    socket.on('error', (err) => {
      error = err;
    });

    // 타임아웃
    socket.setTimeout(2000); // 타임아웃 시간 2000ms로 설정
    socket.on('timeout', () => {
      // 연결이 수립된 적 없이 오류 발생시 타임아웃 오류 처리
      if (!isConnected) {
        error = 'ETIMEDOUT';
      }
      socket.destroy();
    });

    socket.connect(port, host);
  });
}

tcping('example.com', 80).then(console.log).catch(console.error);

실행하면 연결 수립 성공 시 호스트의 IP, 연결 실패 시 오류 메시지가 반환됩니다.





참조한 글

Node.js Documentation - Net