Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/36.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Node.js 与群集模块共享网络端口_Node.js_Sockets - Fatal编程技术网

Node.js 与群集模块共享网络端口

Node.js 与群集模块共享网络端口,node.js,sockets,Node.js,Sockets,根据对的响应,我试图找出为什么在同一端口/地址上有多个工作进程调用server.listen()不会导致任何问题,但在同一端口上有一个旧的工作进程调用server.close()后接一个server.listen()会重复出现错误EADDRINUSE 这似乎不是监听器未正确关闭的情况,因为当我尝试设置新的监听器时,会发出close事件。当此工作进程获得EADDRINUSE时,新生成的工作进程可以调用server.listen(),而不会出现任何问题 下面是一个简单的测试,它将演示这个问题。由于工

根据对的响应,我试图找出为什么在同一端口/地址上有多个工作进程调用
server.listen()
不会导致任何问题,但在同一端口上有一个旧的工作进程调用
server.close()
后接一个
server.listen()
会重复出现错误
EADDRINUSE

这似乎不是监听器未正确关闭的情况,因为当我尝试设置新的监听器时,会发出
close
事件。当此工作进程获得
EADDRINUSE
时,新生成的工作进程可以调用
server.listen()
,而不会出现任何问题

下面是一个简单的测试,它将演示这个问题。由于工作人员每100ms进行一次分叉,他们将在端口16000上建立一个侦听器。当worker 10被分叉时,它将建立一个超时,在1s后关闭其侦听器。一旦发出
close
事件,它将再次尝试调用端口16000上的
server.listen()
,并获取
EADDRINUSE
错误。为了一致性,此测试在绑定期间显式提供相同的地址,以避免处理
null
地址的核心模块出现任何潜在问题

这个特定的实现将导致worker 10在绑定期间遇到错误时占用所有周期,从而防止主进程分叉新的worker。如果在调用
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

该问题似乎是群集模块的内部问题,正在通过节点Github上的跟踪

问题现已更新,并已修复


更新:如果侦听端口0而不是16000(这意味着侦听端口将是随机的,但所有工作人员将使用相同的随机端口),则不会抛出错误,因此我想知道是否是导致错误的原因(虽然这没有多大意义,因为AFAICS意味着端口不匹配,这是不应该的)。通过使用端口0而不是16000,所有初始侦听器都建立在同一端口上(在我的例子中,53230),但每当worker 10启动另一个端口为0的侦听器时,它似乎会增加正在侦听的端口(初始侦听为53230,第二次侦听为53231,等等)。呃,我没有意识到这一点。听起来像是调用
server.listen()
在一个worker中,第二次调用时会遇到很多问题。你能打印出套接字或服务器对象本身吗?这可能会给你提供更多的细节,说明它为什么要再次调用
bind
。我猜在其他worker的情况下,他们知道套接字存在,因此避免调用bind,但在worker 10的情况下,它会错误地调用b我认为套接字没有被绑定。问题是要弄清楚在这个有状态的操作中哪里出错了。