I'm writing a ZooKeeper client to monitor a node. The callback function gets called only the first time I change the data of the node. I'm not sure why the function doesn't execute on the second change.
A second query is that my program terminates if I uncomment the last close() function. As a good practice, I should use the close() function but then it doesn't enter the blocking state to listen to the incoming events. How do I achieve it? I've read the documentation but couldn't find anything useful.
var zookeeper = require("node-zookeeper-client");
var client = zookeeper.createClient("192.168.43.172:2181");
var path = process.argv[2];
client.once("connected", function() {
console.log("Connected to the server.");
client.create(path, new Buffer("data"), function(error) {
if (error) {
console.log("Failed to create node: %s due to: %s.", path, error);
} else {
console.log("Node: %s is successfully created.", path);
}
});
client.getData(
path,
function(event) {
console.log("Got event: %s.", event);
},
function(error, data, stat) {
if (error) {
console.log(error.stack);
return;
}
console.log("Got data: %s", data.toString("utf8"));
}
);
//client.close();
});
client.connect();
I still don't have an answer to my second query but for the first query, the zookeeper server is designed to send an event only the first time a change takes place and then delete the switch. In order to keep receiving the events, I had to set a watch again while handling the triggered event. Below is my code:
var zookeeper = require("node-zookeeper-client");
var client = zookeeper.createClient("192.168.43.172:2181");
var path = process.argv[2];
client.once("connected", function() {
console.log("Connected to the server.");
var watch = function(event) {
console.log("Got event: %s.", event);
client.getData(path, watch, getDat);
};
var getDat = function(error, data, stat) {
if (error) {
console.log(error.stack);
return;
}
console.log("Got data: %s", data.toString("utf8"));
};
client.getData(path, watch, getDat);
// client.close();
});
client.connect();
I want to run these three actions in an ordered manner:
Opening the serial port
Listening to any changes
Sending commands via serial port
The problem is because of the asynchronicity of node js, sometimes data is sent before the port starts listening. Hence, this data is lost. Here is my sample code. How can I solve this problem?
var SerialPort = require("serialport").SerialPort
var serialPort = new SerialPort("COM27", {
baudrate: 57600
}, false); // this is the openImmediately flag [default is true]
//***1***open the serialport
serialPort.open(function (error) {
if ( error ) {
console.log('failed to open: '+error);
}
else {
console.log('open');
}
//***2***port is now listening
serialPort.on('data', function (data) {
console.log('data received: ' + data)
})
//***3***send command using serialport
serialPort.write("AJ+APN?\n", function(err, results) {
console.log('err ' + err);
console.log('results ' + results)
})
});
Create a promise for each of the tasks that should execute in series. Then it should be simple chaining of the promises in the required order.
I don't know about the serialport module you're using, but if it's "standard" in the way it behaves then:
var SerialPort = require("serialport").SerialPort
var serialPort = new SerialPort("COM27", { baudrate: 57600 }, false);
//***1*** listen for events on port
serialPort.on('data', function (data) {
console.log('data received: ' + data);
//***2*** open the serialport
serialPort.open(function (error) {
if ( error ) {
console.log('failed to open: '+error);
} else {
console.log('open');
//***3*** send command using serialport -> after port opened
serialPort.write("AJ+APN?\n", function(err, results) {
console.log('err ' + err);
console.log('results ' + results)
});
}
});
I am new to node.js and would like to connect to a TCP socket. For this I am using the net module.
My idea was to wrap the connect sequence into a function then on the 'close' event, attempt a reconnection. Not that easy apparently.
function conn() {
client.connect(HOST_PORT, HOST_IP, function() {
startSequence();
})
}
client.on('close', function(e) {
log('info','Connection closed! -> ' + e)
client.destroy();
setTimeout(conn(),1000);
});
So when the remote host is closed, I see my logs comming through, howere what seems to be happening is that as soons as the remote host comes online ALL the previous attempts start to get processed - if that makes sense. If you look at client.connect, there is a function called startSequence that sends some data that "iniates" the connection from the remote server side. When the server goes offline and I start reconnecting all the failed attempts from before seem to have been buffered and are all sent together when the server goes online.
I have tried the code from this Stackoverflow link as well to no avail (Nodejs - getting client socket to try again after 5 sec time out)
client.connect(HOST_PORT, HOST_IP, function() {
pmsStartSequence();
})
// Add a 'close' event handler for the client socket
client.on('close', function(e) {
log('debug','connection closed -> ' + e)
client.setTimeout(10000, function() {
log('debug', 'trying to reconnect')
client.connect(HOST_PORT, HOST_IP, function() {
pmsStartSequence();
})
})
});
Is there any advice on how I can reconnect a socket after failure?
Inspired from the other solutions, I wrote this, it's tested, it works !
It will keep on trying every 5 sec, until connection is made, works if it looses connection too.
/* Client connection */
/* --------------------------------------------------------------------------------- */
const client = new net.Socket()
var intervalConnect = false;
function connect() {
client.connect({
port: 1338,
host: '127.0.0.1'
})
}
function launchIntervalConnect() {
if(false != intervalConnect) return
intervalConnect = setInterval(connect, 5000)
}
function clearIntervalConnect() {
if(false == intervalConnect) return
clearInterval(intervalConnect)
intervalConnect = false
}
client.on('connect', () => {
clearIntervalConnect()
logger('connected to server', 'TCP')
client.write('CLIENT connected');
})
client.on('error', (err) => {
logger(err.code, 'TCP ERROR')
launchIntervalConnect()
})
client.on('close', launchIntervalConnect)
client.on('end', launchIntervalConnect)
connect()
The problem is where you set the on-connect callback.
The doc of socket.connect() says:
connectListener ... will be added as a listener for the 'connect' event once.
By setting it in socket.connect() calls, every time you try reconnecting, one more listener (a one-time one), which calls startSequence(), is attached to that socket. Those listeners will not be fired until reconnection successes, so you got all of them triggered at the same time on a single connect.
One possible solution is separating the connect listener from socket.connect() calls.
client.on('connect', function() {
pmsStartSequence();
});
client.on('close', function(e) {
client.setTimeout(10000, function() {
client.connect(HOST_PORT, HOST_IP);
})
});
client.connect(HOST_PORT, HOST_IP);
My solution:
var parentHOST = '192.168.2.66';
var parentPORT = 9735;
var net = require('net');
var S = require('string');
var parentClient = new net.Socket();
var parentActive = false;
var startParentClient = function () {
parentClient = new net.Socket();
parentActive = false;
parentClient.connect(parentPORT, parentHOST, function() {
console.log('Connected ' + cluster.worker.id + ' to parent server: ' + parentHOST + ':' + parentPORT);
parentActive = true;
});
parentClient.on('error', function() {
parentActive = false;
console.log('Parent connection error');
});
parentClient.on('close', function() {
parentActive = false;
console.log('parent connection closed');
setTimeout(startParentClient(), 4000);
});
}
If is necessary connect:
if (!S(parentHOST).isEmpty() && !S(parentPORT).isEmpty()) {
startParentClient();
}
As mentioned multiple times in the comments, you need to use .removeAllListeners() before trying to reconnect your client to the server in order to avoid having multiple listeners on the same event.
The code below should do the trick
Note that I try to reconnect the client after the close and end events because these two events can be fired in different orders after closing a connection
const net = require("net")
let client = new net.Socket()
function connect() {
console.log("new client")
client.connect(
1337,
"127.0.0.1",
() => {
console.log("Connected")
client.write("Hello, server! Love, Client.")
}
)
client.on("data", data => {
console.log("Received: " + data)
})
client.on("close", () => {
console.log("Connection closed")
reconnect()
})
client.on("end", () => {
console.log("Connection ended")
reconnect()
})
client.on("error", console.error)
}
// function that reconnect the client to the server
reconnect = () => {
setTimeout(() => {
client.removeAllListeners() // the important line that enables you to reopen a connection
connect()
}, 1000)
}
connect()
I use the following code to achieve reconnection with node.js. I am not a Javascript expert so I guess it can be improved but it nevertheless works fine for me.
I hope this could help.
Best.
//----------------------------------------------------------------//
// SocketClient //
//----------------------------------------------------------------//
var net = require('net');
var SocketClient = function(host, port, data_handler, attempt)
{
var node_client;
var attempt_index = (attempt ? attempt : 1);
this.m_node_client = new net.Socket();
node_client = this.m_node_client;
this.m_node_client.on('close', function()
{
var new_wrapper = new SocketClient(host, port, data_handler, attempt_index + 1);
node_client.destroy();
new_wrapper.start();
});
this.m_node_client.on('data', data_handler);
this.m_node_client.on('error', function(data)
{
console.log("Error");
});
this.start = function()
{
this.m_node_client.connect(port, host, function()
{
console.log('Connected ' + attempt_index);
});
};
};
//----------------------------------------------------------------//
// Test //
//----------------------------------------------------------------//
var test_handler = function(data)
{
console.log('TestHandler[' + data + ']');
};
var wrapper = new SocketClient('127.0.0.1', 4000, test_handler);
wrapper.start();
I have tried re-using the same socket connection, by using this:
const s = net.createConnection({port});
s.once('end', () => {
s.connect({port}, () => {
});
});
that didn't work, from the server-side's perspective. If the client connection closes, it seems like a best practice to create a new connection:
const s = net.createConnection({port});
s.once('end', () => {
// create a new connection here
s = net.createConnection(...);
});
sad but true lulz.
Following this:
//
// Simple example of using net.Socket but here we capture the
// right events and attempt to re-establish the connection when
// is is closed either because of an error establishing a
// connection or when the server closes the connection.
//
// Requires
const net = require('net');
// Create socket
const port = 5555;
const host = '127.0.0.1';
const timeout = 1000;
let retrying = false;
// Functions to handle socket events
function makeConnection () {
socket.connect(port, host);
}
function connectEventHandler() {
console.log('connected');
retrying = false;
}
function dataEventHandler() {
console.log('data');
}
function endEventHandler() {
// console.log('end');
}
function timeoutEventHandler() {
// console.log('timeout');
}
function drainEventHandler() {
// console.log('drain');
}
function errorEventHandler() {
// console.log('error');
}
function closeEventHandler () {
// console.log('close');
if (!retrying) {
retrying = true;
console.log('Reconnecting...');
}
setTimeout(makeConnection, timeout);
}
// Create socket and bind callbacks
let socket = new net.Socket();
socket.on('connect', connectEventHandler);
socket.on('data', dataEventHandler);
socket.on('end', endEventHandler);
socket.on('timeout', timeoutEventHandler);
socket.on('drain', drainEventHandler);
socket.on('error', errorEventHandler);
socket.on('close', closeEventHandler);
// Connect
console.log('Connecting to ' + host + ':' + port + '...');
makeConnection();
function createServer() {
const client = new net.Socket();
client.connect(HOST_PORT, HOST_IP, function() {
console.log("Connected");
state = 1 - state;
client.write(state.toString());
});
client.on("data", function(data) {
console.log("Received: " + data);
//client.destroy(); // kill client after server's response
});
client.on("close", function() {
console.log("Connection closed");
//client.connect()
setTimeout(createServer, 2000);
});
}
createServer();
Helo,
i create API in Windows Azure Mobile service, In this api script i have function to connect the other service. I have problem how to return value or stop executable my script when i have good answer from service. Function process.exit(1), don't work.
function function1(item,response) {
var buf ='';
var net = require('net');
var HOST = 'xxxx.xxxx.xxxx.xxxx';
var PORT = xxx;
var client = new net.Socket();
client.setTimeout(100000, function() {
console.log("Timeout");
response.send(500, "Timeout");
});
client.connect(PORT, HOST, function() {
client.write(item + "\n");
client.on('data', function(data) {
buf = buf + data.toString('utf-8');
});
client.on('close', function() {
});
client.on('end', function() {
if (buf.length > 1) {
var result = JSON.parse(buf);
//if resulr.Aviable is true the functios should return result or send result and stop execiuting script
if ( result.Avaiable) {
response.send(200, result);
//now i wont't to respond answer to client or return my value(result)
console.log('Send data');
}
}
client.destroy();
});
});
}
One alternative is to have a flag which indicates whether a response has been sent or not. This way, when the first of the alternatives is reached, you can set the flag to true (possibly clearing the timeout so it doesn't linger more than it needs) and in all cases check whether the flag has been set before returning the response. Something along the lines of the code below:
function function1(item,response) {
var buf = '';
var net = require('net');
var HOST = 'xxxx.xxxx.xxxx.xxxx';
var PORT = xxx;
var client = new net.Socket();
var responseSent = false;
var timeoutHandler = client.setTimeout(100000, function() {
if (!responseSent) {
responseSent = true;
console.log("Timeout");
response.send(500, { error: "Timeout" });
}
});
client.connect(PORT, HOST, function() {
client.write(item + "\n");
client.on('data', function(data) {
buf = buf + data.toString('utf-8');
});
client.on('close', function(had_error) {
if (!responseSent) {
clearTimeout(timeoutHandler);
responseSent = true;
console.log('Socket closed');
response.send(500, { error: had_error ? 'Socket error' : 'unknown' });
}
});
client.on('end', function() {
if (!responseSent) {
responseSent = true;
clearTimeout(timeoutHandler);
if (buf.length > 1) {
try {
var result = JSON.parse(buf);
if (result.Available) {
response.send(200, result);
} else {
response.send(500, { error: 'Socket data is not available' });
}
} catch (ex) {
response.send(500, { error: 'error parsing JSON', exception: ex });
}
} else {
// We should always return a response
response.send(500, { error: 'No data read from socket' });
}
}
client.destroy();
});
});
}
Notice that since node.js runs on a single thread, you can assume that there will be no cases where the response is sent twice. Also, you should make sure that the response is always sent once - in the code you had, if there was a socket error, or if buf.length was not greater than 1, or if result.Avaiable was not true, then the timeout response would be sent, but you didn't need to wait for the whole (100 seconds) time to send that response.
I am using tcp sockets in Node.js to communicate with a Java client.
See my very basic server implementation below:
var server = my_http.createServer();
echo.installHandlers(server, {
prefix: '/echo'
});
server.listen(8000, '0.0.0.0');
var socketServer = net.createServer(function (socket) {
// Identify this client
socket.name = socket.remoteAddress + ":" + socket.remotePort
// Put this new client in the list
clients.push(socket);
sockets[socket.name] = socket;
// Handle incoming messages from clients.
socket.on('data', function (data) {
try {
var obj = JSON.parse(data);
if (obj.type == "sendMessage") {
broadcast("{\"id\":\"1\", \"msg\": \"" + obj.msg + "\", \"name\": \"" + obj.name + "\", \"time\": \"" + getDateTime() + "\"}\n", socket);
}
} catch (er) {
}
});
// Remove the client from the list when it leaves
socket.on('end', function () {
try {
clients.splice(clients.indexOf(socket), 1);
} catch (err) {
}
});
// Send a message
function broadcast(message, sender) {
try {
clients.forEach(function (client) {
client.write(message); // ERROR IS HERE
});
} catch (ee) {
}
}
return socket;
}).listen(8080);
For some reason sometimes i get this error:
events.js:71
throw arguments[1]; // Unhandled 'error' event
^
Error: This socket is closed.
Its happening on this line:
client.write(message); // ERROR IS HERE
Any ideas how to prevent this from happening?
or use client.writable to detect if the socket available.
clients.forEach(function (client) {
try {
if (client.writable) {
clientwrite("are u alive");
} else {
console.log('client is not writable');
}
} catch (err) {
console.log("cannot send message.");
}
}
Try this code
Option1
function broadcast(message, sender) {
try {
clients.forEach(function (client) {
if(client._handle){ // ensure there is still underlying handle
client.write(message); // ERROR IS HERE
}
});
} catch (ee) {
}
}
Option2
Attach error event listener on socket.
Socket.on('error',function(){
console.log("%j", arguments);
});