lukew
lukew

Reputation: 431

NodeJS receiving data from PHP server

I'm currently working on a simple NodeJS client that connects to a PHP server using the net classes. In addition, the NodeJS client is working as a Socket.IO server that sends data received from the PHP server to the browsers connected with Socket.IO.

So far, everything is working fine. Yet if I connect with another client to Socket.IO, the PHP server has to send a notification to every connected client. Thus, it sends a JSON-encoded array to the NodeJS client which processes the JSON data (decoding and modifying it a bit).

Now the problem is that sometimes two separate messages sent by the PHP server are concatenated in NodeJS' onData event handling function:

client.on("data", function(data) {

   var msgData = JSON.parse(data.toString("utf8"));
   [...]
}

The variable data now sometimes (not every time!) contains two JSON-strings, such as:

 { "todo":"message", [...] } { "todo":"message", [...] }

This of course results in an exception thrown by the JSON.parse function. I expected two calls of the onData-function with the variable data being:

{ "todo":"message", [...] }

On the PHP server side I have to iterate over an array containing all Socket.IO-connections that are currently served:

foreach($sockets as $id => $client) {

    $nodeJS->sendData($client, array("todo" => "message", [...]);
}

The $nodeJS->sendData-function json-encodes the array and sends it to the NodeJS client:

socket_write($nodeClient, json_encode($dataToSend));

The $nodeJS->sendData function is definitively called two times, as socket_write is.

I now have no idea whether PHP or NodeJS concatenates those two strings. What I want, is that NodeJS calls the onData-handler once for each time the $nodeJS->sendData function is called (e.g. sendData is called twice → the onData-event is fired twice). I could of course add some flag at the end of each json-encoded string and later split them into an array in the onData function. However, I don't like that solution much.

Is there an easier way to accomplish this?

Upvotes: 2

Views: 1491

Answers (2)

ebohlman
ebohlman

Reputation: 15003

It's important to remember that when you're reading from a socket, the data is going to come in arbitrary chunks and its entirely up to your code to split them up into units that are meaningful to process; there is absolutely no guarantee that each chunk will correspond to one meaningful unit.

yannisgu has given you the first part of the solution (terminate each unit with a newline, so your code can tell where it ends): now you need to implement the second part, which is to buffer your incoming data and split it into units.

At initialization, do something like

var buf = '';

and set client's encoding to utf8.

In your "data" handler: [UPDATED: incorporated josh3736's suggestions]

buf += data;
var idx;
while ((idx = buf.indexOf('\n')) >= 0) {
   // there's at least one complete unit buffered up
   var unit = buf.slice(0, idx);
   // extract it
   if (unit.slice(-1) == '\r') {
     // CRLF delimited
     unit = unit.slice(0, -1);
   }
   if (unit.length) {
     // ignore empty strings
     var msgData = JSON.parse(unit);
     [...]
     // process it
   }
   buf = buf.slice(idx +1);
   // discard it
}
// at this point, buf is either empty or contains an incomplete
// unit which will be processed as soon as the rest of it comes in

Upvotes: 4

yannisgu
yannisgu

Reputation: 493

Try to add a new line after the JSON-String on the PHP side.

Upvotes: 1

Related Questions