2012-10-13 20 views
6

Ich habe einen Client/Server implementiert, die über einen TCP-Socket kommunizieren. Die Daten, die ich in den Socket schreibe, sind JSON-Zeichenfolgen. Anfangs funktioniert alles wie erwartet, aber wenn ich die Rate der Schreibvorgänge erhöhe, stoße ich irgendwann auf JSON-Parserfehler, wobei der Anfang auf dem Client den Anfang des neuen Schreibvorgangs am Ende des alten erhält. HierProbleme beim Lesen einer Zeichenfolge aus TCP-Socket in Node.js

ist der Server-Code:

var data = {}; 
data.type = 'req'; 
data.id = 1; 
data.size = 2; 
var string = JSON.stringify(data); 
client.write(string, callback()); 

Hier ist, wie ich diesen Code erhalte auf dem Client-Server:

client.on('data', function(req) { 
    var data = req.toString(); 
    try { 
     json = JSON.parse(data); 
    } catch (err) { 
     console.log("JSON parse error:" + err); 
    } 
}); 

Der Fehler, die ich als die Rate erhöht bin empfangen ist:

Die scheint der Beginn der nächsten Anfrage zu sein, die am Ende der aktuellen markiert wird ein.

Ich habe versucht zu verwenden; als Trennzeichen am Ende jeder Anforderung JSON und dann mit:

var data = req.toString().substring(0,req.toString().indexOf(';')); 

aber dieser Ansatz scheint statt, was zu JSON Parse-Fehler in völlig fehlen einige Anfragen auf der Clientseite zu führen, wie ich die Steigerungsrate schreibt über 300 pro Sekunde.

Gibt es Best Practices oder effizientere Möglichkeiten, eingehende Anfragen über TCP-Sockets zu begrenzen?

Danke!

+0

Es zwei verwandte Fragen ist [[1] (http://stackoverflow.com/questions/ 9962197/node-js-readline-not-warte-für-eine-Zeile-auf-Socket-Verbindungen), [2] (http://stackoverflow.com/questions/7034537/nodejs-what-is-the -proper-to-handling-tcp-socket-streams-which-delimiter)]. In beiden Fällen ist die Lösung die Verwendung von Trennzeichen und das Speichern der Reste der vorherigen Nachricht. Leider scheint eine bessere Lösung noch nicht zu existieren. – mayconbordin

Antwort

23

Vielen Dank für die Erklärungen, sie haben mir geholfen, besser zu verstehen, wie Daten über TCP-Sockets gesendet und empfangen werden. Nachfolgend finden Sie eine kurze Übersicht über den Code, den ich am Ende verwendet:

var chunk = ""; 
client.on('data', function(data) { 
    chunk += data.toString(); // Add string on the end of the variable 'chunk' 
    d_index = chunk.indexOf(';'); // Find the delimiter 

    // While loop to keep going until no delimiter can be found 
    while (d_index > -1) {   
     try { 
      string = chunk.substring(0,d_index); // Create string up until the delimiter 
      json = JSON.parse(string); // Parse the current string 
      process(json); // Function that does something with the current chunk of valid json.   
     } 
     chunk = chunk.substring(d_index+1); // Cuts off the processed chunk 
     d_index = chunk.indexOf(';'); // Find the new delimiter 
    }  
}); 

Kommentare willkommen ...

+0

+1 großartig! Dies löste mein langes ausstehendes gleiches Problem. Vielen Dank. – ajay

+0

gute antwort, danke! –

+1

Sie sollten eine Fanganweisung nach dem Versuch hinzufügen ... –

-3

mit end Ereignis Versuchen und keine Daten, die Sie

var data = ''; 

client.on('data', function (chunk) { 
    data += chunk.toString(); 
}); 

client.on('end', function() { 
    data = JSON.parse(data); // use try catch, because if a man send you other for fun, you're server can crash. 
}); 

Hoffnung Hilfe.

+0

Dies funktioniert nicht mit Nodejs in Socket-Kommunikation –

5

Sie sind auf dem richtigen Weg mit einem Trennzeichen. Sie können das Zeug jedoch nicht einfach vor dem Trennzeichen extrahieren, verarbeiten und dann verwerfen, was danach kam. Sie müssen alles, was Sie nach dem Trennzeichen erhalten haben, puffern und dann verketten, was daneben steht. Das bedeutet, dass Sie nach einem gegebenen data Event eine beliebige Anzahl (einschließlich 0) von JSON "Chunks" erhalten könnten.

Grundsätzlich behalten Sie einen Puffer, den Sie auf "" initialisieren. Auf jedem data Ereignis verketten Sie, was Sie erhalten, bis zum Ende des Puffers und dann split es der Puffer auf dem Begrenzer. Das Ergebnis sind ein oder mehrere Einträge, aber der letzte ist möglicherweise nicht vollständig. Daher müssen Sie den Puffer testen, um sicherzustellen, dass er mit Ihrem Begrenzer endet. Wenn nicht, blenden Sie das letzte Ergebnis ein und setzen Sie Ihren Puffer darauf. Sie verarbeiten dann, was auch immer Ergebnisse bleiben (was nicht sein kann).

2

Beachten Sie, dass TCP keine Garantie dafür gibt, wo es die Datenblöcke teilt, die Sie empfangen. Alles, was es garantiert, ist, dass alle von Ihnen gesendeten Bytes in der richtigen Reihenfolge empfangen werden, es sei denn, die Verbindung schlägt vollständig fehl.

Ich glaube, Node data Ereignisse kommen immer wenn der Sockel sagt, es hat Daten für Sie. Technisch könnten Sie separate data Ereignisse für jedes Byte in Ihren JSON-Daten erhalten und es würde immer noch innerhalb der Grenzen dessen sein, was das Betriebssystem tun darf. Niemand tut das, aber Ihr Code muss so geschrieben werden, als ob er plötzlich jederzeit beginnen könnte, robust zu sein.Es liegt an Ihnen, Datenereignisse zu kombinieren und den Datenstrom dann entlang von Grenzen zu teilen, die für Sie sinnvoll sind.

Um dies zu tun, müssen Sie alle Daten puffern, die nicht "vollständig" sind, einschließlich Daten, die an das Ende eines Teils der "vollständigen" Daten angehängt werden. Wenn Sie ein Trennzeichen verwenden, werfen Sie keine Daten nach dem Trennzeichen weg - behalten Sie es immer als Präfix bei, bis Sie entweder mehr Daten und schließlich entweder ein weiteres Trennzeichen oder das Ende-Ereignis sehen.

Eine andere häufige Wahl besteht darin, alle Daten mit einem Längenfeld zu versehen. Angenommen, Sie verwenden einen festen 64-Bit-Binärwert. Dann warten Sie immer auf 8 Bytes, plus wie viele weitere den Wert in diesen Bytes anzeigen, um anzukommen. Angenommen, Sie haben einen Teil von zehn Datenbytes empfangen. Sie könnten 2 Bytes in einem Ereignis bekommen, dann 5, dann 4 - an diesem Punkt können Sie die Länge analysieren und wissen, dass Sie 7 mehr benötigen, da die letzten 3 Bytes des dritten Blocks Payload waren. Wenn das nächste Ereignis tatsächlich 25 Bytes enthält, würden Sie die ersten 7 zusammen mit den 3 von vor nehmen und das analysieren und nach einem weiteren Längenfeld in den Bytes 8-16 suchen.

Das ist ein künstliches Beispiel, aber bedenken Sie, dass die Netzwerkebene bei niedrigen Verkehrsraten in der Regel Ihre Daten in den von Ihnen angegebenen Teilen aussendet, sodass diese Art von Dingen erst dann wirklich auftaucht, wenn Sie die Last erhöhen . Sobald das Betriebssystem beginnt, Pakete aus mehreren Schreibvorgängen gleichzeitig zu erstellen, beginnt es, sich auf eine Granularität zu verteilen, die für das Netzwerk und nicht für Sie geeignet ist, und Sie müssen damit umgehen.

Verwandte Themen