I am trying to create a simple reply server in node.js
The problem I am having, is that when I telnet into the server, and send a hello, the if loop doesn't catch it, and it goes to the else.
Below is my code:
var net = require('net');
var server = net.createServer(function(socket) {
// Server start
socket.write('Welcome\n');
socket.on('data', function(data) {
dataReceived(socket, data);
});
});
server.listen(8250);
function dataReceived(socket, data) {
if(data == 'hello') {
socket.end('Hi');
} else {
socket.write(data);
socket.end('what??\n');
}
}
Thanks.
Data is a binary buffer, not a string. See http://nodejs.org/docs/v0.4.9/api/buffers.html.
Use the buffer.toString method to convert to a string.
Also, a new line will be added when hitting enter in telnet. Not sure if line endings vary by os, but in this case I'm stripping \r\n.
function dataReceived(socket, data) {
data = data.toString('utf8').replace(/\r\n/, '');
if(data == 'hello') {
socket.end('Hi');
} else {
socket.write(data);
socket.end('what??\n');
}
}
As mentioned, main problem is that you compare Buffer object with string.
There is another problem, most probably not visible in your example.
You don't have control how data is split into packets. 'Hello' sent to your server may result dataReceived called with 'Hel' + 'l' + 'o' buffer 3 times
Correct way to handle 'Hello' input us to create state machine or, more simple and less efficient - buffer all incoming data, look for 'Hello' at the beginning of buffered data, then cut handled data from buffer. There are modules aiming to help to unpack/unframe structured data from input stream, for example node-binary
Related
We're running into a problem where we're getting multiple responses sent from our Node server to a web client which are connected by a socket server (socket.io). By listening with Docklight, I can see that we're really only getting a single response from the serial device, but for some reason the Node server is sending multiples, and they accumulate, so the first time you send a serial command (and it doesn't matter what commands) might only get a couple, next time a couple more, next time a couple more and so on. So if you run several serial commands, you'll get back lots of multiple responses.
Our environment is Windows 7 64 bit, Node V 4.5.0, serialport V 4.0.1. However, this needs to run on Windows, Mac & Linux when we're done. The dev team (me & one other guy) are both fairly new to Node, but otherwise capable developers.
I think what's happening is I'm not using the .flush() & .drain() functions properly and the serialport buffer still contains serial data. Our proprietary devices return either S>, or <Executed/> prompts when a command has completed, so I store the serial response in a buffer until I see one or the other, then process the data (in this example just providing a boolean response whether the device is responding with one or the other or not). For example, if I send a <CR><LF> to one of our devices, it should respond with S> (or <Executed/> depending).
The client calls into the server with this:
socket.on('getDeviceConnected', readDeviceResponse);
function readDeviceResponse(isDeviceResponding) {
console.log('getDeviceConnected');
console.log(isDeviceResponding);
}
function getDeviceConnected() {
console.log("Sending carriage return / line feed.");
socket.emit('getDeviceConnected', '\r\n');
}
And on the server, here's what I'm trying:
socket.on('getDeviceConnected', function (connectionData) {
//write over serial buffer before the write occurs to prevent command accumulation in the buffer.
serialBuffer = '';
sbeSerialPort.write(connectionData, function (err, results) {
//since there's no way to tell if the serial device hasn't responded, set a time out to return a false after allowing one second to elapse
setTimeout(function () {
console.log('Inside getDeviceConnected setTimeout');
console.log('Is serial device responding:', isSerialDeviceResponding);
if (!isSerialDeviceResponding) {
console.log('Serial device timed out.');
socket.emit('getDeviceConnected', false);
}
}, 1000);
if (err) {
console.log('Serial port error level:', err);
}
if (results) {
if (results === 2) {
console.log('Serial port is responding');
}
}
});
sbeSerialPort.on('data', function (serialData) {
isSerialDeviceResponding = true;
console.log('Does S> prompt exist?', serialData.lastIndexOf('S>'));
while(!serialData.lastIndexOf('S>') > -1 || !serialData.lastIndexOf('<Executed/>') > -1){
serialBuffer += serialData;
break;
}
if (isSerialDeviceResponding) {
socket.emit('getDeviceConnected', true);
isSerialDeviceResponding = true;
}
sbeSerialPort.flush(function (err, results) {
if (err) {
console.log(err);
return;
}
if(results){
console.log('Serial port flush return code:', results);
}
});
});
I'm not very sure about the .flush() implementation here, and I've omitted the .drain() part because neither of them seems to do much of anything (assuming they were correctly implemented).
How do I insure that there is no data left in the serialport buffer when the .write() command is complete? Or do you see other problems with how I'm handling the serial data?
Edit, Source code up on pastebin.com:
Server.js
Client.js
HTML
I am pretty new to Node.Js and I'm using tcp sockets to communicate with a client. Since the received data is fragmented I noticed that it prints "ondata" to the console more than once. I need to be able to read all the data and concatenate it in order to implement the other functions. I read the following http://blog.nodejs.org/2012/12/20/streams2/ and thought I can use socket.on('end',...) for this purpose. But it never prints "end" to the console.
Here is my code:
Client.prototype.send = function send(req, cb) {
var self = this;
var buffer = protocol.encodeRequest(req);
var header = new Buffer(16);
var packet = Buffer.concat([ header, buffer ], 16 + buffer.length);
function cleanup() {
self.socket.removeListener('data', ondata);
self.socket.removeListener('error', onerror);
}
var body = '';
function ondata() {
var chunk = this.read() || '';
body += chunk;
console.log('ondata');
}
self.socket.on('readable', ondata);
self.socket.on('end', function() {
console.log('end');
});
function onerror(err) {
cleanup();
cb(err);
}
self.socket.on('error', onerror);
self.socket.write(packet);
};
The end event will handle the FIN package of the TCP protocol (in other words: will handle the close package)
Event: 'end'#
Emitted when the other end of the socket sends a FIN packet.
By default (allowHalfOpen == false) the socket will destroy its file descriptor once it has written out its pending write queue. However, by setting allowHalfOpen == true the socket will not automatically end() its side allowing the user to write arbitrary amounts of data, with the caveat that the user is required to end() their side now.
About FIN package: https://en.wikipedia.org/wiki/Transmission_Control_Protocol#Connection_termination
The solution
I understand your problem, the network communication have some data transfer gaps and it split your message in some packages. You just want read your fully content.
For solve this problem i will recommend you create a protocol. Just send a number with the size of your message before and while the size of your concatenated message was less than total of your message size, keep concatenating :)
I have created a lib yesterday to simplify that issue: https://www.npmjs.com/package/node-easysocket
I hope it helps :)
how do I handle the CONTROL+C input in a node.js TCP server?
var server = net.createServer(function(c) {
c.on('end', function() {
console.log('Client disconnected');
});
c.on('data', function(data) {
if (data == "CONTROL+C") { // Here is the check
c.destroy();
}
});
}).listen(8124);
Control-C is a single byte, 0x03 (using an ASCII chart is kinda helpful).
However, whenever you're dealing with a socket connection you have to remember that you're going to receive data in a "chunked" fashion and the chunking does not necessarily correspond to the way the data was sent; you cannot assume that one send call on the client side corresponds to a single chunk on the server side. Therefore you can't assume that if the client sends a Control-C, it will be the only thing you receive in your data event. Some other data might come before it, and some other data might come after it, all in the same event. You will have to look for it inside your data.
From ebohlman's answer. It work.
c.on('data', function(data) {
if (data.toString().charCodeAt(0) === 3) {
c.destroy();
}
});
I am trying to learn about streams in node.js!
server.js
var net = require("net");
var server = net.createServer(function(conn) {
conn.write("welcome!");
# echo the user input!
conn.pipe(conn);
});
server.listen("1111", function() {
console.log("port 1111 opened");
});
telnet test
The server currently echos the user's input
$ telnet localhost 1111
welcome!
hello
hello
desired output
To demonstrate where/how I should process the stream on the server side, I would like to wrap the user's input in {} before echoing it back
$ telnet localhost 1111
welcome!
hello
{hello}
This will basically accomplish the exact output you've requested:
var net = require('net');
var server = net.createServer(function(c) {
c.setEncoding('utf8');
c.on('data', function(d) {
c.write('{' + d.trim() + '}\n');
});
});
server.listen(9871);
First let me call your attention to c.setEncoding('utf8'). This will set a flag on the connection that will automatically convert the incoming Buffer to a String in the utf8 space. This works well for your example, but just note that for improved performance between Sockets it would be better to perform Buffer manipulations.
Simulating the entirety of .pipe() will take a bit more code.
.pipe() is a method of the Stream prototype, which can be found in lib/stream.js. If you take a look at the file you'll see quite a bit more code than what I've shown above. For demonstration, here's an excerpt:
function ondata(chunk) {
if (dest.writable) {
if (false === dest.write(chunk) && source.pause) {
source.pause();
}
}
}
source.on('data', ondata);
First a check is made if the destination is writable. If not, then there is no reason to attempt writing the data. Next the check if dest.write === false. From the documentation:
[.write] returns true if the entire data was flushed successfully to the kernel buffer. Returns false if all or part of the data was queued in user memory.
Since Streams live in kernel space, outside of the v8 memory space, it is possible to crash your machine by filling up memory (instead of just crashing the node app). So checking if the message has drained is a safety prevention mechanism. If it hasn't finished draining, then the source will be paused until the drain event is emitted. Here is the drain event:
function ondrain() {
if (source.readable && source.resume) {
source.resume();
}
}
dest.on('drain', ondrain);
Now there is a lot more we could cover with how .pipe() handles errors, cleans up its own event emitters, etc. but I think we've covered the basics.
Note: When sending a large string, it is possible that it will be sent in multiple packets. For this reason it may be necessary to do something like the following:
var net = require('net');
var server = net.createServer(function(c) {
var tmp = '';
c.setEncoding('utf8');
c.on('data', function(d) {
if (d.charCodeAt(d.length - 1) !== 10) {
tmp += d;
} else {
c.write('{' + tmp + d.trim() + '}\n');
tmp = '';
}
});
});
server.listen(9871);
Here we use the assumption that the string is ended by the new line character (\n, or ascii character code 10). We check the end of the message to see if this is the case. If not, then we temporarily store the message from the connection until the new line character is received.
This may not be a problem for your application, but thought it would be worth noting.
you can do something like
conn.on 'data', (d) ->
conn.write "{#{d}}"
the .pipe method is basically just attaching the data event of the input stream to write to the output stream
I'm not sure about net() actually, but I imagine it's quite similar to http:
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/event-stream'});
http.get(options, function(resp){
resp.on('data', function(chunk){
res.write("event: meetup\n");
res.write("data: "+chunk.toString()+"\n\n");
});
}).on("error", function(e){
console.log("Got error: " + e.message);
});
});
https://github.com/chovy/nodejs-stream
I connected wavecom GSM modem on ubantu. I use node.js language to communicate with GSM modem.
I send command to modem by Child Process. Here example
var spawn = require("child_process").spawn,
exec = require('child_process').exec;
// Write dev_ttyUSB15.tmp file
var child = exec('cat < /dev/ttyUSB15 > /tmp/dev_ttyUSB15.tmp');
// Read dev_ttyUSB15.tmp file
var m1 = spawn('tail',['-f','/tmp/dev_ttyUSB15.tmp']);
// on data event is emitted when dev_ttyUSB15.tmp file has some data
m1.stdout.on('data', function (data) {
console.log("Data : "+data); // this is executed as output
});
Now When I fire some command on port /dev/ttyUSB15 I do not get output properly.
E.g
Suppose my output should be
Data : abcd1234
but instead of it I got
Data : abc
Data : d1234
In short My output is breaked.
I can not extrapolate from where my output exactly break. It's random.
Can anyone give me any idea?
Thanks in advance.
As all streams in node.js, the reading of data consists of 2 separate events: data and end.
data event is fired when some data is readable in the stream (in your case, twice).
end event is fired when no more data events will be fired.
var blob = "";
m1.stdout.on('data', function (data) {
blob += data;
});
m1.stdout.on('end', function () {
console.log("Data : " + blob); // here you have all the data within one variable
});
It's hard to say without knowing what protocol you are speaking with the modem, but if it's e.g. \n delimited, you will have to buffer the data and split on \n:
var buffer = '';
m1.stdout.on('data', function(data) {
var received = (buffer + data).split('\n');
buffer = received.pop().trim();
console.log(received.join(''));
});