Nodejs检测端口是否被占用

Node.js 检测端口是否被占用:原生无依赖方案(附批量检测)

用 Node.js 实现检测指定端口是否被占用的方案,以下提供两种实用写法(原生 net 模块,无第三方依赖),包括「单个端口检测」和「批量端口检测」,代码可直接运行,适配日常开发/运维场景。

一、核心原理

Node.js 内置的 net 模块可创建 TCP 服务器,核心逻辑:

  1. 尝试让服务器监听指定端口;
  2. 若监听失败且错误码为 EADDRINUSE → 端口被占用;
  3. 若监听成功 → 端口未被占用(需立即关闭服务器,避免占用端口)。

这种方式是最可靠的原生方案,无需安装任何依赖,适配所有 Node.js 版本。

二、完整实现代码

1. 基础版:检测单个端口是否被占用

封装为 Promise 函数,支持异步调用(推荐,适配 async/await):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
const net = require('net');

/**
* 检测指定端口是否被占用
* @param {number} port - 要检测的端口号(如 3000)
* @param {string} host - 可选,检测的主机(默认 127.0.0.1)
* @returns {Promise<boolean>} - true=被占用,false=未被占用
*/
function checkPortIsUsed(port, host = '127.0.0.1') {
return new Promise((resolve) => {
// 创建TCP服务器
const server = net.createServer();
// 禁用默认的延迟关闭,加快检测速度
server.unref();

// 监听错误(核心:捕获端口占用错误)
server.on('error', (err) => {
// EADDRINUSE = 地址/端口已被占用
if (err.code === 'EADDRINUSE') {
resolve(true); // 端口被占用
} else {
// 其他错误(如端口越界、主机不可达),也视为"不可用"
resolve(true);
}
});

// 监听成功 = 端口未被占用
server.listen(port, host, () => {
server.close(); // 立即关闭服务器,释放端口
resolve(false); // 端口未被占用
});
});
}

// ===================== 调用示例 =====================
// 检测 3000 端口是否被占用
async function testSinglePort() {
const port = 3000;
const isUsed = await checkPortIsUsed(port);
console.log(`端口 ${port} ${isUsed ? '已被占用' : '未被占用'}`);
}

// 执行检测
testSinglePort();

2. 进阶版:批量检测多个端口

适合一次性检测多个常用端口(如 3000、8080、9000):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
const net = require('net');

// 复用单个端口检测函数
function checkPortIsUsed(port, host = '127.0.0.1') {
return new Promise((resolve) => {
const server = net.createServer().unref();
server.on('error', (err) => resolve(err.code === 'EADDRINUSE'));
server.listen(port, host, () => {
server.close();
resolve(false);
});
});
}

/**
* 批量检测多个端口的占用状态
* @param {number[]} ports - 端口数组(如 [3000, 8080, 9000])
* @returns {Promise<object>} - 结果对象 { 3000: true, 8080: false }
*/
async function checkMultiPorts(ports) {
const result = {};
// 并行检测(效率更高)
const promises = ports.map(async (port) => {
result[port] = await checkPortIsUsed(port);
});
await Promise.all(promises);
return result;
}

// ===================== 调用示例 =====================
async function testMultiPorts() {
const ports = [3000, 8080, 9000, 80, 443];
const portStatus = await checkMultiPorts(ports);

// 格式化输出结果
console.log('批量端口检测结果:');
Object.entries(portStatus).forEach(([port, isUsed]) => {
console.log(`端口 ${port}${isUsed ? '✅ 已占用' : '❌ 未占用'}`);
});
}

// 执行批量检测
testMultiPorts();

三、关键细节说明

  1. **server.unref()**:禁用服务器的“引用计数”,避免检测脚本因服务器未关闭而一直运行;
  2. **错误码 EADDRINUSE**:Node.js 中表示“地址已被占用”的标准错误码,是判断端口占用的核心依据;
  3. 异步封装:用 Promise 封装,适配 async/await,避免回调地狱,符合现代 Node.js 开发习惯;
  4. **主机参数 host**:默认检测本地(127.0.0.1),若需检测外网端口,可传入公网 IP/域名(如 0.0.0.0)。

四、扩展场景:检测端口占用后自动选可用端口

开发中常用的“端口被占用则自动换端口”功能,基于上述函数实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* 从指定起始端口开始,找到第一个未被占用的端口
* @param {number} startPort - 起始端口(如 3000)
* @returns {Promise<number>} - 可用端口号
*/
async function findAvailablePort(startPort) {
let currentPort = startPort;
// 循环检测,直到找到可用端口
while (currentPort < 65535) { // 端口最大为 65535
const isUsed = await checkPortIsUsed(currentPort);
if (!isUsed) {
return currentPort;
}
currentPort++;
}
throw new Error('未找到可用端口(1-65535)');
}

// 调用示例:从 3000 开始找可用端口
findAvailablePort(3000).then((port) => {
console.log(`找到可用端口:${port}`);
// 后续可启动服务:如 express/app.listen(port)
});

总结

关键点回顾

  1. 核心原理:通过 net.createServer() 尝试监听端口,捕获 EADDRINUSE 错误判断占用;
  2. 基础用法:单个端口检测封装为 Promise 函数,异步调用更友好;
  3. 进阶用法:批量检测/自动找可用端口,适配开发场景;
  4. 优势:原生无依赖、跨平台(Windows/Linux/macOS 通用)、结果可靠。

Nodejs检测端口是否被占用
https://cszy.top/2018-05-18 nodejs检测端口是否被占用/
作者
csorz
发布于
2018年5月18日
许可协议