节点.js集群模块不会在 http 上释放套接字/端口.Server.close().

Node.js cluster module doesn't release socket/port on http.Server.close()

本文关键字:套接字 释放 端口 Server close http js 模块 节点      更新时间:2023-09-26

在 Node.js 脚本中,我正在尝试打开一些端口/套接字,然后再次关闭它们。我在使用 Node.js 群集模块时遇到问题。它似乎不像不使用集群模块时相同的代码那样关闭端口。

例如,采用以下代码创建 5 http。服务器在自己的端口上,然后关闭除最后一个(第 5 个)之外的所有端口。

'use strict';
var http = require('http');
function goGoGadget(i) {
    console.log('var i = ', i);
    var httpServer = http.createServer();
    var nextPort = 4000 + i;
    console.log('about to listen on port', nextPort);
    httpServer.listen(nextPort);
    if (i < 5) {
        httpServer.on('listening', function() {
            console.log('closing port:', nextPort);
            httpServer.close(function() {
                console.log('closed server on port:', nextPort);
            });
        });
    }
}
goGoGadget(1);
goGoGadget(2);
goGoGadget(3);
goGoGadget(4);
goGoGadget(5);

正如预期的那样,节点.js仅打开一个端口:

dhcp50:test marco$ lsof -i -n -P | grep node
node      20895 marco   16u  IPv4 0xb242422d2e0e2bb1      0t0  TCP *:4005 (LISTEN)

然后,使用相同的代码,但使用群集模块在工作线程中运行:

'use strict';
var cluster = require('cluster');
var http = require('http');
function goGoGadget(i) {
    console.log('var i = ', i);
    var httpServer = http.createServer();
    var nextPort = 4000 + i;
    console.log('about to listen on port', nextPort);
    httpServer.listen(nextPort);
    if (i < 5) {
        httpServer.on('listening', function() {
            console.log('closing port:', nextPort);
            httpServer.close(function() {
                console.log('closed server on port:', nextPort);
            });
        });
    }
}
if (cluster.isMaster) {
    var numWorkers = 5;
    for (var i = 0; i < numWorkers; i += 1) {
        console.log ('forking ', i + 1);
        cluster.fork();
    }
}
else {
    goGoGadget(cluster.worker.id);
}

这一次,Node.js 继续保留前 4 个 http 的端口。服务器,即使它们已关闭:

dhcp50:test marco$ lsof -i -n -P | grep node
node      20900 marco   17u  IPv4 0xb242422d2d9682e1      0t0  TCP *:4004 (LISTEN)
node      20900 marco   18u  IPv4 0xb242422d2d5faa11      0t0  TCP *:4001 (LISTEN)
node      20900 marco   19u  IPv4 0xb242422d2d5fd621      0t0  TCP *:4005 (LISTEN)
node      20900 marco   20u  IPv4 0xb242422d2d985141      0t0  TCP *:4002 (LISTEN)
node      20900 marco   21u  IPv4 0xb242422d2d9862e1      0t0  TCP *:4003 (LISTEN)
node      20905 marco   13u  IPv4 0xb242422d2d5fd621      0t0  TCP *:4005 (LISTEN)

的问题很简单:为什么?我如何让他们关闭?我怀疑如果我在网络中使用排他性选项。Server.listen() 端口可能会关闭,但 http.Server.listen() API 似乎没有将此选项哈希作为参数。

这个问题的起源来自使用幻像节点(带有幻像)在使用群集模块的 Express.js 应用程序中随着时间的推移打开许多页面时的问题。为了确保在创建新的幻像节点实例时没有端口冲突,并避免EADDRINUSE,我进行了端口扫描并检查我将要使用的端口是否可用。问题变成了,随着时间的推移,越来越多的端口被打开,并且由于它们从未关闭,节点最终会崩溃并出现EMFILE错误。

似乎,所描述的问题出现在 Node v0.11.1 上。从 0.11.2 开始,套接字在关闭时成功取消链接。由此提交修复。

凉。

我注意到的可能是您答案的一部分:有时,当要求关闭时,系统不会释放端口。我遇到了这个问题,一个小的 shell 脚本永远关闭(nodejs 持久性模块),从 git 中提取新代码并重新启动它。服务器不会再次启动,因为它显示"端口 xxxx 已在使用中"。