与Cluster模块共享网络端口

时间:2016-05-09 15:29:09

标签: node.js sockets

根据对this question的回复,我试图弄清楚为什么多个工作人员在同一个端口/地址上调用server.listen()不会导致任何问题,但是有一个旧的工人呼叫server.close()后跟同一端口上的server.listen()会反复出现错误EADDRINUSE

似乎并不是侦听器未正确关闭的情况,因为发出了close事件,这是我尝试设置新侦听器的时候。当这名工作人员获得EADDRINUSE时,新生的工人可以在没有问题的情况下致电server.listen()

这是一个简单的测试,可以证明这个问题。由于工作人员每100毫秒分叉一次,他们将在端口16000上建立一个监听器。当工作人员10分叉时,它将建立一个超时以在1秒后拆除其监听器。发出close事件后,它将再次尝试在端口16000上调用server.listen()并收到EADDRINUSE错误。为了保持一致性,此测试在绑定期间显式提供相同的地址,以避免处理null地址的核心模块的任何潜在问题。

这个特定的实现将使工作者10在绑定期间一旦遇到错误就占用所有周期,从而使主进程不会分叉新工作者。如果在调用server.listen()之前添加了延迟,则工作人员10仍然会继续点击EADDRINUSE,而主人不断请求能够建立听众的新工作人员。

var cluster = require('cluster');
var net     = require('net');

if (cluster.isMaster) {
    setInterval(function(){cluster.fork()},100);
} else {
    var workerID = cluster.worker.id;
    var server;
    var setup = function() {
        console.log('Worker ' + workerID + ' setting up listener');
        server = net.createServer(function(stream) {});
        server.on('error', function(err) {
            console.log('Error on worker ' + workerID, err);
            teardown();
        });
        if (workerID == 10) {
            server.listen(16000, '127.0.0.1', function() {
                console.log('Worker ' + workerID + ' listener established');
                setTimeout(teardown, 1000);
            });
        } else {
            server.listen(16000, '127.0.0.1', function() {
                console.log('Worker ' + workerID + ' listener established');
            });
        }
    }
    var teardown = function() {
        console.log('Worker ' + workerID + ' closing listener');
        server.close(setup);
    }
    setup();
}

此测试用例的初始输出:

Worker 1 setting up listener
Worker 1 listener established
Worker 2 setting up listener
Worker 2 listener established
Worker 3 setting up listener
Worker 3 listener established
Worker 4 setting up listener
Worker 4 listener established
Worker 5 setting up listener
Worker 5 listener established
Worker 6 setting up listener
Worker 6 listener established
Worker 7 setting up listener
Worker 7 listener established
Worker 8 setting up listener
Worker 8 listener established
Worker 9 setting up listener
Worker 9 listener established
Worker 10 setting up listener
Worker 10 listener established
Worker 11 setting up listener
Worker 11 listener established
Worker 12 setting up listener
Worker 12 listener established
Worker 13 setting up listener
Worker 13 listener established
Worker 14 setting up listener
Worker 14 listener established
Worker 15 setting up listener
Worker 15 listener established
Worker 16 setting up listener
Worker 16 listener established
Worker 17 setting up listener
Worker 17 listener established
Worker 18 setting up listener
Worker 18 listener established
Worker 19 setting up listener
Worker 19 listener established
Worker 10 closing listener
Worker 10 setting up listener
Error on worker 10 { [Error: bind EADDRINUSE 127.0.0.1:16000]
  code: 'EADDRINUSE',
  errno: 'EADDRINUSE',
  syscall: 'bind',
  address: '127.0.0.1',
  port: 16000 }
Worker 10 closing listener
Worker 10 setting up listener
Error on worker 10 { [Error: bind EADDRINUSE 127.0.0.1:16000]
  code: 'EADDRINUSE',
  errno: 'EADDRINUSE',
  syscall: 'bind',
  address: '127.0.0.1',
  port: 16000 }
Worker 10 closing listener

1 个答案:

答案 0 :(得分:3)

该问题似乎是群集模块的内部问题,并且正在通过节点Github上的this issue进行跟踪。

问题现已更新并已修复为已解决。

更新:此修复程序在v6.2.1中可用