Frage node.js - Umgang mit TCP-Socket-Fehler ECONNREFUSED


Ich verwende node.js mit socket.io, um meiner Webseite Zugriff auf Zeichendaten zu geben, die von einem TCP-Socket bedient werden. Ich bin ziemlich neu bei node.js.

Benutzer  ----> Website  <- (socket.io) -> node.js  <- (TCP) -> TCP-Server

Der Code ist gnädig kurz:

io.on('connection', function (webSocket) {
    tcpConnection = net.connect(5558, 'localhost', function() {});

    tcpConnection.on('error', function(error) {
        webSocket.emit('error', error);
        tcpConnection.close();
    });

    tcpConnection.on('data', function(tcpData) {
        webSocket.emit('data', { data: String.fromCharCode.apply(null, new Uint8Array(tcpData))});
    });
});

Im Normalfall funktioniert alles einwandfrei, aber ich kann nicht garantieren, dass der TCP-Server immer da ist. Wenn dies nicht der Fall ist, gibt der TCP-Stack ECONNREFUSED an node.js zurück - dies wird vollständig erwartet, und ich muss es elegant behandeln. Momentan sehe ich:

events.js:72
    throw er; // Unhandled 'error' event
          ^
Error: connect ECONNREFUSED
    at errnoException (net.js:904:11)
    at Object.afterConnect [as oncomplete] (net.js:895:19)

... und der ganze Prozess endet.

Ich habe viel nach Lösungen dafür gesucht; Die meisten Hits scheinen von Programmierern zu stammen, die fragen, warum ECONNREFUSED überhaupt empfangen wird - und der Rat lautet einfach, sicherzustellen, dass der TCP-Server verfügbar ist. Keine Behandlung von Fehlerfällen.

Dieser Beitrag - Node.js connectListener hat immer noch einen Socket-Fehler aufgerufen - schlägt vor, einen Handler für das Ereignis 'error' hinzuzufügen, wie ich es oben im Code getan habe. Genau so würde es mir gefallen ... außer es nicht (für mich), mein Programm fängt ECONNREFUSED nicht ein.

Ich habe versucht, RTFM, und die node.js Dokumente bei http://nodejs.org/api/net.html#net_event_error_1 vorschlagen, dass es tatsächlich ein "Fehler" -Ereignis gibt - aber geben Sie wenig Ahnung, wie man es benutzt.

Antworten auf andere ähnliche SO-Posts (wie Node.js Fehler: Verbinden Sie ECONNREFUSED ) berate einen globalen, nicht abgefangenen Exception-Handler, aber das scheint mir eine schlechte Lösung zu sein. Das ist nicht mein Programm, das eine Ausnahme wegen des schlechten Codes wirft, es funktioniert gut - es soll externe Störungen behandeln, wie es entworfen ist.

Damit

  • Komme ich dem richtig zu? (Ich gebe gerne zu, dass dies ein Anfängerfehler ist)
  • Ist es möglich zu tun, was ich tun möchte, und wenn ja, wie?

Oh und:

$ node -v
v0.10.31

13
2017-09-15 10:56


Ursprung


Antworten:


Ich habe den folgenden Code ausgeführt:

var net = require('net');

var client = net.connect(5558, 'localhost', function() {
  console.log("bla");
});
client.on('error', function(ex) {
  console.log("handled error");
  console.log(ex);
});

Da ich 5558 nicht geöffnet habe, war die Ausgabe:

$ node test.js
handled error
{ [Error: connect ECONNREFUSED]
  code: 'ECONNREFUSED',
  errno: 'ECONNREFUSED',
  syscall: 'connect' }

Dies beweist, dass der Fehler gut behandelt wird ... was darauf hindeutet, dass der Fehler an einem anderen Ort auftritt.

Wie in einer anderen Antwort besprochen, ist das Problem eigentlich diese Zeile:

webSocket.emit('error', error);

Das Ereignis 'Fehler' ist speziell und muss irgendwo behandelt werden (wenn dies nicht der Fall ist, endet der Prozess).

Wenn Sie das Ereignis einfach in "Problem" oder "Warnung" umbenennen, wird das gesamte Fehlerobjekt über den Socket.io-Socket an die Webseite zurückgegeben:

webSocket.emit('warning', error);

14
2017-09-15 11:30



OK, etwas peinlich, stellt sich heraus, dass das Problem tatsächlich diese Linie ist:

webSocket.emit('error', error);

Meine Absicht war gewesen:

  • TCP-Fehler abfangen (z. B. ECONNREFUSED)
  • "wirf sie" über den Socket.io-Socket auf die Client-Webseite zurück
  • Handle sie in irgendeiner Weise auf der Webseite (natürlich mit einigen Nacharbeit / Desinfektion in irgendeiner Weise für die Anzeige für den Benutzer)

Das "Fehler" -Ereignis ist jedoch speziell und muss irgendwo behandelt werden (was ich nicht getan habe - daher der Prozessende).

Das Umbenennen des Ereignisses in "Problem" führt dazu, dass das gesamte Fehlerobjekt über den Socket.io-Socket zurück zur Webseite übertragen wird:

webSocket.emit('problem', error);

2
2017-09-15 13:33



Der einzige Weg, den ich gefunden habe, um das zu beheben, besteht darin, das Netzmaterial in eine Domain zu packen:

const domain = require('domain');
const net = require('net');

const d = domain.create();

d.on('error', (domainErr) => {
    console.log(domainErr.message);
});

d.run(() => {
    const client = net.createConnection(options, () => {

        client.on('error', (err) => {
            throw err;
        });
        client.write(...);
        client.on('data', (data) => {
            ...
        });
    });
});

Der Domänenfehler erfasst Fehlerbedingungen, die auftreten, bevor der Netzclient erstellt wurde, z. B. ein ungültiger Host.

Siehe auch: https://nodejs.org/api/domain.html


0
2018-04-23 12:46