Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

nodejs socket programming - send data length

I have a server listening on specific port and expects commands the following way -

First four bytes should contain the length of the command and remaining bytes contains the actual command. For example:

If the command I want to send is {cmd:"EL",ptno:1234}, the first four bytes I send should contain the number 20 in them in big-endian notation as the command length is 20 as the commands are in UTF-8 format. The remaining bytes I send will have the command in them.

I want to know how to do this in nodejs. Also when the server sends data back, I need to read the first four bytes and determine the data length and read the socket input stream accordingly. Please help.

like image 945
Vijay Muvva Avatar asked May 29 '26 19:05

Vijay Muvva


1 Answers

I've did a lib that does EXACTLY what you need: https://www.npmjs.com/package/node-easysocket (except by writing 4 bytes in Little Endian, but it is very easy to fix)

About your question, here we go:

For send a message, is much more easy than receive, you just need convert you message to a ByteArray and prepend an integer (4 bytes Big Endian) containing the size of your ByteArray + 4:

var buffer = new Buffer("Hello World or a JSON String", "binary");

//create a buffer with +4 bytes
var consolidatedBuffer = new Buffer(4 + buffer.length);

//write at the beginning of the buffer, the total size
consolidatedBuffer.writeInt32BE(buffer.length, 0);

//Copy the message buffer to the consolidated buffer at position 4     (after the 4 bytes about the size)
buffer.copy(consolidatedBuffer, 4);

//Send the consolidated buffer
socket.write(consolidatedBuffer, function(err) {
     if (err) console.log(err)
});

if you want to read, it will be a bit more complex, because you have the possibility to you read a buffer spliced in chunks.

Example: My buffer have 10mb of size but my network connection can transfer ~100 bytes per second, so the server will receive a lot of pieces of data and you will need store them until it complete the necessary size according the length informed in the first 4 bytes.

The Javascript is a dynamic language, so I can create a runtime property the the socket object to store the collected chunks:

socket.on('data', function(data) {
    console.log("server bytes in:"+data.length);
    receive(socket,data);
});


function receive(socket, data){
    //Create a chunk prop if it does not exist
    if(!socket.chunk){
        socket.chunck = {
            messageSize : 0,
            buffer: new Buffer(0),
            bufferStack: new Buffer(0)
        };
    }
    //store the incoming data
    socket.chunck.bufferStack = Buffer.concat([socket.chunck.bufferStack, data]);
    //this is to check if you have a second message incoming in the tail of the first
    var reCheck = false;
    do {
        reCheck = false;
        //if message size == 0 you got a new message so read the message size (first 4 bytes)
        if (socket.chunck.messageSize == 0 && socket.chunck.bufferStack.length >= 4) {
            socket.chunck.messageSize = socket.chunck.bufferStack.readInt32BE(0);
        }

        //After read the message size (!= 0) and the bufferstack is completed and/or the incoming data contains more data (the next message)
        if (socket.chunck.messageSize != 0 && socket.chunck.bufferStack.length >= socket.chunck.messageSize + 4) {
            var buffer = socket.chunck.bufferStack.slice(4, socket.chunck.messageSize + 4);
            socket.chunck.messageSize = 0;
            socket.chunck.bufferStack = socket.chunck.bufferStack.slice(buffer.length + 4);
            onMessage(socket, buffer);
            //if the stack contains more data after read the entire message, maybe you got a new message, so it will verify the next 4 bytes and so on...
            reCheck = socket.chunck.bufferStack.length > 0;
        }
    } while (reCheck);
}

function onMessage(socket, buffer){
    console.log("message received from: "+socket+" with data:"+buffer.toString()+");
}
like image 200
Irineu Antunes Avatar answered Jun 01 '26 08:06

Irineu Antunes