Nodejs 官方API 中 server.listen() 的一个 demo的疑惑
Nodejs 官方API 中 server.listen() 的一个 demo的疑惑
官方API的 net.Server 中 server.listen 有个 demo
server.on('error', function (e) {
if (e.code == 'EADDRINUSE') {
console.log('Address in use, retrying...');
setTimeout(function () {
server.close();
server.listen(PORT, HOST);
}, 1000);
}
});
error 事件触发之后不是会马上触发 close 事件的么?在 setTimeout 的回调中加入 server.close() 不仅多余,而且如果 server 已经 close 掉不是还是抛出异常?
当然可以。你提到的代码片段是 Node.js 官方文档中 net.Server
类的 server.listen()
方法的一个示例,用于处理端口已经被占用的情况。你的疑问在于为什么在这个错误处理逻辑中需要调用 server.close()
和重新调用 server.listen()
。
首先,让我们解释一下这段代码的逻辑:
- 当服务器尝试绑定到一个已经被其他进程使用的端口时,会触发
'error'
事件,并传递一个错误对象e
。 - 如果错误代码
e.code
等于'EADDRINUSE'
(表示地址已被使用),则说明端口被占用。 - 在这种情况下,程序通过
setTimeout
设置了一个延迟,以便稍后重试绑定操作。 setTimeout
的回调函数中,先关闭当前服务器实例(server.close()
),然后重新尝试绑定到指定的端口(server.listen(PORT, HOST)
)。
关于你的疑问,确实,当 'error'
事件被触发时,理论上服务器可能已经处于关闭状态,因此直接调用 server.close()
可能会导致问题。然而,这里的 server.close()
调用实际上是为了确保服务器完全停止运行,从而避免潜在的竞态条件。如果不关闭服务器就立即尝试重新绑定,可能会导致一些不确定的行为或错误。
为了更好地理解,这里提供一个简化版的示例代码:
const net = require('net');
const PORT = 8080;
const HOST = 'localhost';
const server = net.createServer();
server.on('error', function (e) {
if (e.code === 'EADDRINUSE') {
console.log('Address in use, retrying...');
// 关闭当前服务器实例
server.close(() => {
// 5秒后重新尝试绑定
setTimeout(() => {
server.listen(PORT, HOST, () => {
console.log(`Server is listening on ${HOST}:${PORT}`);
});
}, 5000);
});
}
});
// 尝试首次绑定
server.listen(PORT, HOST, () => {
console.log(`Server is listening on ${HOST}:${PORT}`);
});
在这个简化版本中,我们添加了 server.close()
的回调函数,在服务器成功关闭后再设置定时器来重新绑定。这确保了服务器在重新尝试绑定之前已完全停止运行。这样可以避免由于未关闭的服务器实例而导致的任何潜在问题。
看起来是这样:调用server.close()方法会关闭server,如果成功关闭,触发close事件。官网对close()的解释如下:
server.close([callback]) Stops the server from accepting new connections and keeps existing connections. This function is asynchronous, the server is finally closed when all connections are ended and the server emits a ‘close’ event. Optionally, you can pass a callback to listen for the ‘close’ event.
在 Node.js 的 net.Server
中,server.listen()
方法用于启动服务器并监听指定端口。当发生错误(例如端口已被占用)时,会触发 'error'
事件。官方文档中的示例展示了如何处理这种情况,以确保服务器在端口被占用时能够重试。
示例代码解析:
- 当服务器遇到错误(如地址已占用)时,捕获到
'error'
事件。 - 检查错误码是否为
'EADDRINUSE'
,如果是,则表示端口已被占用。 - 在 1 秒后重新尝试绑定端口,并关闭当前服务器实例。
针对你的问题,关于 'error'
事件后是否立即触发 'close'
事件:
- 在大多数情况下,
'error'
事件不会立即导致'close'
事件触发。 - 除非你在错误处理逻辑中显式调用
server.close()
,否则不会触发'close'
事件。 - 示例代码中的
server.close()
是为了在重试前释放资源,防止重复绑定端口时出现冲突。
以下是简化后的代码示例:
const net = require('net');
const PORT = 3000;
const HOST = 'localhost';
const server = net.createServer();
server.on('error', (e) => {
if (e.code === 'EADDRINUSE') {
console.log('Address in use, retrying...');
setTimeout(() => {
server.close();
server.listen(PORT, HOST);
}, 1000);
}
});
// 绑定端口
server.listen(PORT, HOST, () => {
console.log(`Server listening on ${HOST}:${PORT}`);
});
这段代码展示了如何处理端口被占用的情况,并在 1 秒后重试绑定。这样可以确保服务器能够正常启动并监听指定端口。