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

时间:2015-03-12 08:35:10

标签: javascript node.js sockets phantomjs

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

例如,使用以下代码在其自己的端口上创建5个http.Server,然后关闭除最后一个(第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);

正如预期的那样,node.js只打开了一个端口:

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

然后,使用Cluster模块在worker中运行相同的代码:

'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.Server的端口,即使它们已被关闭:

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)

我的问题很简单:为什么?我如何让它们关闭?我怀疑如果我在net.Server.listen()中使用 exclusive 选项,端口可能会关闭,但http.Server.listen() API似乎不会将此选项哈希作为参数。< / p>

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

2 个答案:

答案 0 :(得分:1)

似乎所描述的问题通过Node v0.11.1出现。从0.11.2开始,套接字在关闭时成功取消链接。由this commit修正。

冷却。

答案 1 :(得分:0)

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