2012-10-13 14 views
6

Ho implementato un client/server che comunica utilizzando un socket TCP. I dati che sto scrivendo sul socket sono JSON con stringhe. Inizialmente tutto funziona come previsto, tuttavia, mentre aumento il tasso di scritture, alla fine mi imbatto in errori di analisi JSON in cui l'inizio sul client riceve l'inizio della nuova scrittura alla fine di quella precedente.Problemi durante la lettura di una stringa dal socket TCP in Node.js

Ecco il codice del server:

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

Ecco come sto ricevendo questo codice sul server client:

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

L'errore che sto ricevendo con l'aumentare dei tassi è:

SyntaxError: Unexpected token { 

Quale sembra essere l'inizio della prossima richiesta taggata alla fine della corrente uno.

Ho provato a usare; come delimitatore alla fine di ogni richiesta JSON e quindi utilizzando:

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

Tuttavia questo approccio, invece di conseguente errori di analisi JSON sembra comportare manca completamente alcune richieste sul lato client, come ho aumentare il tasso di scrive oltre 300 al secondo.

Esistono buone pratiche o metodi più efficienti per delimitare le richieste in arrivo tramite socket TCP?

Grazie!

+0

Ci sono due questioni correlate [[1] (http://stackoverflow.com/questions/ 9962197/node-js-readline-not-waiting-for-a-full-line-on-socket-connections), [2] (http://stackoverflow.com/questions/7034537/nodejs-what-is-the -proper-way-to-movimentazione-tcp-zoccolo-stream-che-delimitatore)]. In entrambi la soluzione è l'uso di delimitatori, oltre a memorizzare gli avanzi del messaggio precedente. Sfortunatamente una soluzione migliore non sembra ancora esistere. – mayconbordin

risposta

23

Grazie a tutti per le spiegazioni, mi hanno aiutato a capire meglio il modo in cui i dati vengono inviati e ricevuti tramite socket TCP. Di seguito una breve panoramica del codice che ho usato alla fine:

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 
    }  
}); 

Commenti benvenuto ...

+0

+1 great! questo ha risolto il mio lungo problema in sospeso. Grazie. – ajay

+0

buona risposta, grazie! –

+1

È necessario aggiungere una dichiarazione di cattura dopo aver provato ... –

-3

Prova con end evento e nessun dato

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. 
}); 

Speranza aiuto.

+0

Questo non funziona con nodejs nella comunicazione socket –

5

Sei sulla strada giusta con l'utilizzo di un delimitatore. Tuttavia, non puoi semplicemente estrarre la roba prima del delimitatore, elaborarla e quindi scartare ciò che è venuto dopo. Devi recuperare tutto ciò che hai dopo il delimitatore e quindi concatenare ciò che viene dopo. Ciò significa che potresti finire con qualsiasi numero (incluso 0) di "pezzi" JSON dopo un determinato evento data.

In pratica si mantiene un buffer, che viene inizializzato su "". Su ciascun evento data si concatena tutto ciò che si riceve alla fine del buffer e quindi split il buffer sul delimitatore è. Il risultato sarà una o più voci, ma l'ultima potrebbe non essere completa, quindi è necessario testare il buffer per assicurarsi che termini con il delimitatore. In caso contrario, si apre l'ultimo risultato e si imposta il buffer su di esso. Elaborate quindi qualsiasi risultato rimanga (che potrebbe non esserlo).

2

Tenere presente che TCP non fornisce alcuna garanzia su dove divide i blocchi di dati ricevuti. Tutto ciò garantisce che tutti i byte inviati verranno ricevuti in ordine, a meno che la connessione non abbia esito positivo.

Credo che gli eventi del nodo data vengano visualizzati ogni volta che il socket dice che ha dati per voi. Tecnicamente potresti ottenere eventi separati data per ogni byte nei tuoi dati JSON e sarebbe comunque entro i limiti di ciò che il sistema operativo è autorizzato a fare. Nessuno lo fa, ma il tuo codice deve essere scritto come se potesse improvvisamente iniziare ad accadere in qualsiasi momento per essere robusto.Sta a te combinare gli eventi dei dati e quindi ri-dividere il flusso di dati lungo i confini che hanno senso per te.

Per fare ciò, è necessario bufferizzare tutti i dati che non sono "completi", inclusi i dati aggiunti alla fine di un blocco di dati "completi". Se stai usando un delimitatore, non buttare via alcun dato dopo il delimitatore - mantienilo sempre come prefisso finché non vedi più dati e alla fine un altro delimitatore o l'evento finale.

Un'altra scelta comune è il prefisso di tutti i dati con un campo di lunghezza. Supponiamo che tu usi un valore binario fisso a 64 bit. Quindi si attendono sempre 8 byte, più altri ancora il valore in quei byte indica, per arrivare. Supponiamo che tu abbia ricevuto una porzione di dieci byte di dati in arrivo. Potresti ottenere 2 byte in un evento, poi 5, poi 4 - a quel punto puoi analizzare la lunghezza e sapere che hai bisogno di altri 7, poiché gli ultimi 3 byte del terzo blocco erano payload. Se il prossimo evento contiene effettivamente 25 byte, prendi il primo 7 insieme al 3 di prima e analizzalo e cerca un altro campo di lunghezza nei byte 8-16.

Questo è un esempio forzato, ma essere consapevoli che a tassi a basso traffico, il livello di rete generalmente inviare i tuoi dati in qualsiasi pezzi si dà, in modo da questo genere di cose veramente solo comincia a mostrare come si aumenta il carico . Una volta che il sistema operativo inizia a creare pacchetti da più scritture contemporaneamente, inizierà a suddividersi in una granularità che è conveniente per la rete e non per te, e devi affrontarla.

Problemi correlati