Node net data merge when multiple write

Viewed 324

I am using Node net.

When the client multiple writes feeds, and on the server-side, it received 1 data.

var net           = require('net');

// SERVER SIDE
var net_port   = 8080; // node net port
var server = net.createServer(function(connection){
   connection.on('data', function(data){
          var str = data.toString();
          console.log("Received, Length: "+str.length); // IT SHOULD be 25 in length
    });
   connection.pipe(connection);
});

server.listen(net_port, function() { 
   console.log('server is listening');
});
// SERVER CODE NED

// ### CLIENT SIDE

var client = net.connect({port: 8080}, function() {
   console.log('connected to server!');  
});


string = "acdefghijklmnopqrstuvwxyz"; // 25 char
setInterval(function(){
    client.write(string);
    client.write(string);
},1);
setInterval(function(){
    client.write(string);
    client.write(string);
},1);

Sending string with length 25, but when received OUTPUT IS

Received, Length: 25
Received, Length: 25
Received, Length: 75  // merged 3 data
Received, Length: 100 // merged 4 data
Received, Length: 25
Received, Length: 50 // merge 2 times
Received, Length: 75
Received, Length: 25
Received, Length: 25
Received, Length: 25
Received, Length: 100

IN reality, in my actual code, I cant use split string, because if a client sends String length 100 4 times. so server received

Received, Length: 100
Received, Length: 220
Received, Length: 80

How I can force Node Net to send and received actual data.

Fiddle: https://www.mycompiler.io/view/BJGjA87

1 Answers

net.createServer creates a TCP server. TCP sockets are stream-based, not datagram-based. They don’t have a concept of message boundaries: everything is just a one contiguous stream of bytes with no markers distinguishing which fragments were sent together and which separately. If you want to establish boundaries between messages sent over a TCP socket, you have to delineate them yourself: either by postulating that each message must have a fixed length in bytes, or by introducing markers that establish where one message ends and another starts.

Below, as an example, is a simple modification of your server that uses the json-seq format defined in RFC 7464 to that end. More long-term, you may look into making it a WebSocket server instead, using a library such as ws. It would probably be more robust than the code below; this is mostly just a demonstration.

var net = require('net');

var server = net.createServer(function (connection) {
    var buffer = '';
    
    function receivedMessage(value) {
        console.log('received: ' + JSON.stringify(value));
    }
    
    function protocolError() {
        console.log('protocol error');
        connection.close();
    }
    
    function parseMessages(buf) {
        console.log('parsing ' + buf.length + ' code units worth of messages');
        if (buf.substring(0, 1) !== '\x1e') {
            protocolError();
            return;
        }
        var m, rx = /\x1e([^\x1e]*)/g;
        while (m = rx.exec(buffer)) {
            if (m[1] === '')
                continue;
            try {
                var value = JSON.parse(m[1]);
            } catch (e) {
                if (e instanceof SyntaxError)
                    continue;   // RFC 7464 §2.3
                throw e;
            }
            receivedMessage(value);
        }       
    }
    
    connection.on('data', function (data) {
        buffer += data.toString('utf8');
        console.log(buffer.length + ' code units in the buffer');
        var lastRS = buffer.lastIndexOf('\x1e');
        if (lastRS === 0)
            return;
        var fullMessages = buffer.substring(0, lastRS);
        buffer = buffer.substring(lastRS, buffer.length);
        parseMessages(fullMessages);
        try {
            var value = JSON.parse(buffer);
        } catch (e) {
            if (e instanceof SyntaxError)
                return;  // maybe just truncated; defer error until later
            throw e;
        }
        receivedMessage(value);
        buffer = '';
    });

    connection.on('close', function () {
        console.log('closed');
        parseMessages(buffer);
    });
});

server.listen(8080, function() { 
    console.log('server is listening');
});

And here’s an appropriately-modified client:

var net = require('net');

var client = net.connect({port: 8080}, function() {
   console.log('connected to server!');  
});

function sendMessage(value) {
    client.write(Buffer.from('\x1e' + JSON.stringify(value) + '\n', 'utf8'));
}

string = 'acdefghijklmnopqrstuvwxyz';

setInterval(function(){
    sendMessage(string);
    sendMessage(string);
}, 1);

setInterval(function(){
    sendMessage(string);
    sendMessage(string);
}, 1);
Related