I'm new to Node.js and I am writing a client to consume a text-based TCP stream from a server. For testing purposes, I want to simulate the server in Node so I can test with no other dependencies.
I have a file of captured data that looks like:
$X,... <-- broadcast every second
$A,...
$A,...
$B,...
$X,... <-- broadcast every second
$A,...
$A,...
$C,...
$X,... <-- broadcast every second
The server emits a line starting with $X every second. The other records are broadcast as events happen. How can I modify my network server below to broadcast this data and throttle it so it emits one line at a time and pauses for one second every time it encounters a line starting with $X?
Here is my code so far which reads in the data and broadcasts it over a port:
var http = require('http')
, fs = require('fs')
;
var server = http.createServer(function (req, res) {
var stream = fs.createReadStream(__dirname + '/data.txt');
stream.pipe(res);
});
server.listen(8000);
console.log('server running on 8000');
This works but obviously just streams out the whole file at warp speed. What I want is to spit out all of the lines from one $X to the next, pause for one second (close enough for testing purposes) and then continue to the next $X and so on like:
> telnet 127.0.0.1 8000
$X,...
$A,...
$A,...
$B,...
(output would pause for one second)
$X,...
$A,...
$A,...
$C,...
(output would pause for one second)
$X,...
...
In my example above, the broadcast always starts from the beginning of data.txt when I connect with a client. Ideally, this server would keep broadcasting this data in a loop, allowing clients to disconnect and reconnect at any time and start receiving data wherever the server simulator was currently at.
(PS - data.txt is a relatively small file, < 1MB in most cases)
UPDATE -
Thanks to Laurent's pointer, I was able to get it working with the following:
var net = require('net'),
fs = require('fs'),
async = require('async');
var server = net.createServer(function (socket) {
var lines = fs.readFileSync(__dirname + '/data-small.txt').toString().split(/\n+/);
async.whilst(
function () {
return lines.length > 0;
},
function (done) {
var line = lines.shift();
socket.write(line + '\r\n');
setTimeout(done, /^\$X,/.test(line) ? 1000 : 0);
},
function (err) {
// no more lines present
socket.end();
});
});
server.listen(8000);
console.log('server running on 8000');
I'm now getting a blast of lines until an $X, a 1s pause, and then it continues! Thanks!
Drilling into my 2nd part: is there a way to synchronize output of this faux server so all clients see the same output regardless of when they connect?
If you want to keep all clients in sync, you need to do something entirely different. Here's a starting point. Also, it seems like the net module would be a better fit.
var net = require('net'),
fs = require('fs'),
_ = require('underscore');
var current = 0,
sockets = [];
// dirty parser for blocs
var data = fs.readFileSync(__dirname + '/data.txt').toString(),
blocs = _.chain(data.split(/\$X,/)).compact().map(function (bloc) {
return '$X,' + bloc;
}).value();
function streamBloc() {
console.log('writing bloc #' + current + ' to ' + sockets.length + ' sockets');
_(sockets).each(function (socket) {
socket.write(blocs[current]);
});
current = (current + 1) % blocs.length;
setTimeout(streamBloc, 1000);
}
var server = net.createServer(function (socket) {
console.log('incoming connection');
// immediately write current bloc
socket.write(blocs[current]);
// add to sockets so that it receive future blocs
sockets.push(socket);
// cleanup when the client leaves
socket.on('end', function () {
sockets = _(sockets).without(socket);
});
}).listen(8000, function () {
console.log('server listening on port 8000');
});
streamBloc();
Related
I wrote a UDP client to send lines from standard input to an UDP socket:
var PORT = 12000;
var HOST = '127.0.0.1';
var dgram = require('dgram');
var client = dgram.createSocket('udp4');
process.stdin.on("readable",
function() {
var chunk = process.stdin.read();
if (chunk !== null) {
client.send(chunk, PORT, HOST);
}
}
);
client.on("message",
function (message, remote) {
process.stdout.write(message);
}
);
Now, the readable event fires on the first time but stops working afterwards.
I successfully used this on a TCP chat client and server before: I got a readable event infinitely.
What could cause the problem here?
The code works if I subscribe to the data event on standard input. That fires every time I type a new line into the standard input.
See data event documentation at Stream class.
I've read through the site and googled, and can't seem to find an answer that will work for me.
I've set up a super super basic example of using Socket.IO until I can get my head around, all it does is passes a number to the back end, adds +1 and send it back to front end.
It does work however, each interval round, it emits more and more (which I can see using console.log on the server side.) I'm only connected using one computer to test.
Can someone help me please. I understand its probably because the emit is inside the connection but I just can't quite click in my head on how to overcome this.
I've tried moving bits around, moving the function out of the connection. I've tried multiple ideas from google, but nothing seems to solve it.
const io = require('socket.io')();
io.on('connection', (socket) => {
socket.on('subscribeToAddition', (additon,interval) => {
console.log('current number... ', additon);
setInterval(() => {
socket.emit('addition', additon+1);
}, interval);
});
});
const port = 8000;
io.listen(port);
console.log('listening on port ', port);
the interval variable is set as 5 seconds in my react component. I just want it to log/update once every five seconds instead of log once, then twice, then 4 times, then 8 times, etc
Given the symptoms, it's likely that you're sending the subscribeToAddition event more than once on the same socket and thus starting more than one timer for the same socket and thus you get duplicate messages.
Proper indentation of your code makes things a little clearer:
const io = require('socket.io')();
io.on('connection', (socket) => {
socket.on('subscribeToAddition', (additon, interval) => {
console.log('current number... ', additon);
setInterval(() => {
socket.emit('addition', additon + 1);
}, interval);
});
});
const port = 8000;
io.listen(port);
console.log('listening on port ', port);
I want to make sure you understand that setInterval() starts a repeating timer that goes forever until you call clearInterval() on the timerId that it returns.
Problems I see:
In every subscribeToAddition message, you're adding a new setInterval() timer. So, if you send the subscribeToAddition twice, you will have two setInterval() timers each going on the same socket.
Those setInterval() timers will accumulate and never go away because you have no way of the client stopping them and they don't go away even when the socket closes. They will just cause errors because socket.emit() won't work on a closed socket, but they will probably even prevent garbage collection of the old socket.
It is not clear exactly how you want this to work, but here's a cleaned up version:
const io = require('socket.io')();
io.on('connection', (socket) => {
function clearTimer() {
if (socket.myTimer) {
clearInterval(socket.myTimer);
delete socket.myTimer;
}
}
socket.on('subscribeToAddition', (additon, interval) => {
console.log('current number... ', additon);
// don't start a new interval timer if one is already running
if (!socket.mytimer) {
socket.mytimer = setInterval(() => {
socket.emit('addition', ++additon);
}, interval);
}
});
socket.on('unSubscribeToAddition', () => {
clearTimer();
});
socket.on('disconnect', () => {
clearTimer();
});
});
const port = 8000;
io.listen(port);
console.log('listening on port ', port);
This version makes the following modifications:
Keeps track of the timerID from setInterval() so we can stop it in the future. For convenience, we store it as a custom property on the socket object so that each connected socket has its own timer.
Adds an unsubscribeToAddition message so the client can stop the timer.
Adds a disconnect message handler so you can stop the timer when the socket disconnects.
Increments the additon variable on each tick of the timer.
I am creating a socket pass through inspector.
Basically, I start up a socket server (net.createServer) and a socket client (net.connect). For testing purposes, I do not have a endpoint socket waiting.
I want test whether the endpoint socket is available. If not, nodejs should wait until socket is available.
var net = require('net');
var inbound = net.createServer();
var outbound = net.connect({
port: 8193
});
inbound.listen(8192, function () { //'listening' listener
address = inbound.address();
console.log('Server started on %j', address);
});
inbound.on('connection', function (insock, outbound) {
console.log('CONNECTED ' + insock.remoteAddress + ':' + insock.remotePort);
insock.on('data', function (data, outbound) {
outbound.write(data);
console.log('DATA ' + data);
});
});
The best way to test whether any resource is available is to try to use it. Pre-testing is liable to a number of objections:
If it tests something different from the actual usage, it may yield an incorrect answer.
If it tests the same things as the actual usage it is merely wastefully redundant.
The situation may change between the test and the usage.
Trying to send data from a serial device to web clients. I am using a serial to network proxy, ser2Net to make the data available to a server that acts on the data and sends a manipulated version of the data to web clients. The clients specify the location of the ser2net host and port. The core of this action is coded in node.js as shown here:
function getDataStream(socket, dataSourcePort, host) {
var dataStream = net.createConnection(dataSourcePort, host),
dataLine = "";
dataStream.on('error', function(error){
socket.emit('error',{message:"Source not found on host:"+ host + " port:"+dataSourcePort});
console.log(error);
});
dataStream.on('connect', function(){
socket.emit('connected',{message:"Data Source Found"});
});
dataStream.on('close', function(){
console.log("Close socket");
});
dataStream.on('end',function(){
console.log('socket ended');
dataConnection.emit('lost',{connectInfo:{host:host,port:dataSourcePort}});
});
dataStream.on('data', function(data) {
// Collect a line from the host
line += data.toString();
// Split collected data by delimiter
line.split(delimiter).forEach(function (part, i, array) {
if (i !== array.length-1) { // Fully delimited line.
//push on to buffer and emit when bufferSendCommand is present
dataLine = part.trim();
buffer.push(part.trim());
if(part.substring(0, bufferSendCommand.length) == bufferSendCommand){
gotALine.emit('new', buffer);
buffer=[];
}
}
else {
// Last split part might be partial. We can't announce it just yet.
line = part;
}
});
});
return dataStream;
}
io.sockets.on('connection', function(socket){
var stream = getDataStream(socket, dataSourcePort, host);
//dispense incoming data from data server
gotALine.on('new', function(buffer){
socket.emit('feed', {feedLines: buffer});
});
dataConnection.on('lost', function(connectInfo){
setTimeout(function(){
console.log("Trying --- to reconnect ");
stream = getDataStream(socket, connectInfo.port, connectInfo.host);
},5000);
});
// Handle Client request to change stream
socket.on('message',function(data) {
var clientMessage = JSON.parse(data);
if('connectString' in clientMessage
&& clientMessage.connectString.dataHost !== ''
&& clientMessage.connectString.dataPort !== '') {
stream.destroy();
stream = getDataStream(socket,
clientMessage.connectString.dataPort,
clientMessage.connectString.dataHost);
}
});
});
This works well enough until the serial device drops off and ser2net stops sending data. My attempt to catch the end of the socket and reconnect is not working. The event gets emitted properly but the setTimeout only goes once. I would like to find a way to keep on trying to reconnect while sending a message to the client informing or retry attempts. I am node.js newbie and this may not be the best way to do this. Any suggestions would be appreciated.
Ok I think I figured it out in the dataStream.on('data' ... I added a setTimeout
clearTimeout(connectionMonitor);
connectionMonitor = setTimeout(function(){doReconnect(socket);}, someThresholdTime);
The timeout executes if data stops coming in, as it is repeatedly cleared each time data comes in. The doReconnect function keeps trying to connect and sends a message to the client saying something bad is going on.
I'm getting a weird result when writing to a socket. I wrote a simple experiment with a client and a server:
server.js
var net = require('net');
net.createServer(function (connection) {
connection.on('data', function (data) {
console.log('data: ' + data);
});
}).listen(1337);
client.js
var net = require('net');
var client = net.connect({port: 1337}, function () {
var i = 0;
function send() {
client.write('a');
if (++i < 100) {
process.nextTick(send);
} else {
client.end();
}
}
send();
});
I expected the server to show 100 lines of data: a, but I ended up getting a smaller number of data: aaaaaaa lines. There's socket.setNoDelay() that seems to be what I want, but it doesn't seem to have any effect.
What am I missing?
Thanks a lot,
The TCP protocol only sends exactly the bytes you write in the socket. They will not be separated into messages, that's up to you. If you would like to get 100 lines of a then you would have to define 100 separate messages, and choose a delimiter for them. Usually people delimit messages sent to a TCP socket by \r\n.
So you would need to change your server to
var net = require('net');
net.createServer(function (connection) {
connection.on('data', function (buffer) {
var data = buffer.toString();
if (data.indexOf('\r\n') > -1) { // If there's more than one line in the buffer
var lines = data.split('\r\n'); // Split the lines
var i = lines.length;
while (i--) { // This will read your lines in reverse, be careful
console.log(lines[i]); // Print each line
}
} else {
console.log(data); // If only one line came through, print it
}
});
}).listen(1337);
And your client to
var net = require('net');
var client = net.connect({port: 1337}, function () {
var i = 0;
function send() {
client.write('a\r\n'); // Notice the \r\n part. This is what will help you separate messages on the server
if (++i < 100) {
process.nextTick(send);
} else {
client.end();
}
}
send();
});
And then I believe you would get 100 lines of a.
This module also provides a very interesting way to do it, and of course ZeroMQ would also shine in this because it already has a nice protocol that puts things in envelopes and sends them.
Also interestingly but out of the scope of your question, the messages you send write to the socket on one side will not arrive in the same order on the server. If you change your send function to
function send() {
if (++i < 100) {
client.write('a'+i+'\r\n');
process.nextTick(send);
} else {
client.end();
}
}
you can see them arriving not in the order you sent them.
By "The TCP protocol only sends exactly the bytes you write in the socket" I mean that if you do socket.write("1"); socket.write("2"), you will receive "12" on the server, because that's what you wrote on the socket. You have to explicitly separate your messages by something so that the server can know when a message starts and when a message ends.
About receiving things in order or not, you'll notice that if you remove the process.nexTick and have your client like:
var net = require('net');
var client = net.connect({port: 1337}, function () {
var i = 100;
while (i--) {
client.write('a'+i+'\r\n');
}
});
you'll get two messages on the server (at least I got): first numbers 83 - 99 and then 0 - 82, despite having wrote them in order.
Its because TCP splits it in packets in some magic way. The first package was actually larger than the second one, so it got there last. You can read more about how TCP works in the wikipedia page of course, and this video is probably going to say more than what you need to hear but its good to understand everything you're working with.