Basierend auf den Antworten auf this question, versuche ich herauszufinden, warum mehrere Arbeiter server.listen()
auf dem gleichen Port/Adresse anrufen keine Probleme verursacht, aber mit einem alten Worker-Aufruf server.close()
gefolgt von einem server.listen()
auf dem gleichen Port wird wiederholt den Fehler EADDRINUSE
geben.Gemeinsam Net-Ports mit dem Cluster-Modul
Es scheint nicht der Fall zu sein, dass der Listener nicht korrekt schließt, da ein close
-Ereignis ausgegeben wird, wenn ich versuche, den neuen Listener einzurichten. Während dieser Arbeiter EADDRINUSE
erhält, können neu hervorgebrachte Arbeiter server.listen()
ohne Probleme anrufen.
Hier ist ein einfacher Test, der das Problem demonstrieren wird. Wenn Arbeiter alle 100ms gegabelt werden, stellen sie einen Listener auf Port 16000 her. Wenn Worker 10 gegabelt ist, wird ein Zeitlimit eingerichtet, um seinen Listener nach 1s abzureißen. Sobald ein close
Ereignis ausgegeben wird, versucht es, server.listen()
erneut auf Port 16000 aufzurufen und den EADDRINUSE
Fehler zu erhalten. Aus Konsistenzgründen stellt dieser Test beim Binden explizit die gleiche Adresse bereit, um mögliche Probleme mit Kernmodulen zu vermeiden, die sich mit einer null
-Adresse befassen.
Diese spezielle Implementierung führt dazu, dass der Worker 10 dann alle Zyklen aufnimmt, sobald er den Fehler während des Bindens trifft, wodurch der Hauptprozess daran gehindert wird, neue Worker abzuzweigen. Wenn vor dem Aufruf von server.listen()
eine Verzögerung hinzugefügt wird, wird Arbeiter 10 weiterhin weiterhin EADDRINUSE
erreichen, während der Master ständig neue Worker abgibt, die in der Lage sind, Listener einzurichten.
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();
}
Anfängliche Ausgabe von diesem Testfall:
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
verfügbar Wenn Sie Port 0 statt 16000 hören (was bedeutet, dass der Listening-Port wird zufällig, sondern alle Arbeitnehmer, die gleichen zufälligen Port verwenden werden), um den Fehler wird nicht geworfen, also frage ich mich, ob [dieser Code] (https://github.com/nodejs/node/blob/cee4c25c9281d106f80b20ba7854bf9003f9357a/lib/net.js#L1310-L1315) den Fehler verursacht (obwohl es nicht funktioniert Es macht keinen Sinn, denn AFAICS würde bedeuten, dass es in Häfen keine Übereinstimmung gibt, die es nicht geben sollte. – robertklep
Wenn Port 0 anstelle von 16000 verwendet wird, werden alle ursprünglichen Listener auf demselben Port (in meinem Fall 53230) eingerichtet, aber wenn Worker 10 einen anderen Listener mit Port 0 startet, scheint er den Port zu inkrementieren (53230 für das erste Hören, 53231 für das zweite Hören usw.). –
Ugh, das habe ich nicht bemerkt. Es hört sich an, als würde "server.listen()" in einem Worker ein zweites Mal mit Problemen behaftet sein. – robertklep