Node.js TCPポートスキャナーの実装 - net.Socketとタイムアウト処理
問題
特定のホストのポートが開いているか確認したい。pingはICMPなのでポート単位の確認ができず、外部ライブラリを入れるほどの作業でもありません。
解決方法
const net = require('net');
async function checkPort(host, port, timeout = 500) {
return new Promise((resolve) => {
const socket = new net.Socket();
const timer = setTimeout(() => {
socket.destroy();
resolve({ host, port, open: false });
}, timeout);
socket.on('connect', () => {
clearTimeout(timer);
socket.destroy();
resolve({ host, port, open: true });
});
socket.on('error', () => {
clearTimeout(timer);
resolve({ host, port, open: false });
});
socket.connect(port, host);
});
}
// 使用例:複数ポートを同時スキャン
async function scanPorts(host, ports) {
const results = await Promise.all(
ports.map(port => checkPort(host, port))
);
return results.filter(r => r.open);
}
ポイント
rejectの代わりにresolveで統一するのがポイントです。ポートが閉じているのはエラーではなく正常な結果なので、Promise.allが途中で停止しません。- タイムアウトはLAN環境では500msで十分です。インターネットのホストをスキャンする場合は2000〜3000msに増やす必要があります。
socket.destroy()を必ず呼び出してください。呼ばないとソケットが開いたままになり、数百ポートを同時スキャンするとファイルディスクリプタが枯渇します。