How to reconnect a socket using native WebSocket library in Chrome - node.js

I have this:
<script>
const socket = new WebSocket('ws://localhost:3702');
socket.addEventListener('open', function (event) {
console.log('connection made to server:', event);
});
socket.addEventListener('message', function (event) {
console.log('ws client received message:', event);
location.reload();
});
</script>
it won't auto-reconnect, if the server restarts. What is the best way to reconnect to the server?

You need to detect the connection-close event and write a reconnect function to try to reconnect to the server:
socket.addEventListener('close', function (event) {
console.log('Disconnected!');
reconnect(); //----------> tries to reconnect through the websocket
});
Notice that it might take a long time for the close event to fire. In which case you can implement a simple ping-pong method as described here to detect the connection is dropped (instead of the close event).
You can find a simple implementation of a reconnect function here.

So looks like there is no reconnect option, which makes sense for a lower-level library. This reconnect logic worked fine:
const createConnection = () => {
const socket = new WebSocket('ws://localhost:3702');
socket.addEventListener('open', function (event) {
console.log('connection made to server:', event);
});
socket.addEventListener('close', function (event) {
console.log('connection closed:', event);
socket.close();
setTimeout(createConnection, 2500); // reconnect here
});
socket.addEventListener('message', function (event) {
console.log('ws client received message:', event);
location.reload();
});
};
once the connection is closed ('close' event occurs because the server restarts), then we wait 2.5 seconds and then attempt to reconnect. If the reconnect fails, then the close event re-fires, so we just try again 2.5 seconds later.

Related

socket.io client can't connect/reconnect reliably

I am utilizing socket.io V3.1.1 and am trying to figure out how to get the client to reconnect after the connection is disconnected due to a phone going asleep. When I run the code, it connects, refreshes an order, and then I press the power button on the iPhone to cause it to sleep. I then press the home key, and I see a disconnect event, followed by a connect event which refreshes the order. If I repeat the process, I see it disconnect, but I never see a connect event.
The question is, how does one reliably connect/reconnect and/or why don't I get additional connect events?
Here's a sample console.log output:
connect
refreshOrder 1234
disconnect due to transport error
connect
refreshOrder 1234
disconnect due to transport error
and then no more events
Here's the primary code that's involved:
const socket = io("wss://xyz.org:3000");
socket.on('connect', () => {
console.log("connect");
if (order_id !== null){
refreshOrder(order_id);
}
});
socket.on("disconnect", (reason) => {
console.log("disconnect due to " + reason);
socket.connect();
});
I also have the following event handlers, but they never get called:
socket.on('reconnect', () => {
console.log('reconnect');
if (order_id !== null){
refreshOrder(order_id);
}
});
socket.on("connect_error", (err) => {
console.log("connect_error: " + err);
setTimeout(() => {
console.log("socket.connect retry");
socket.connect();
}, 1000);
});
The answer is that you should ignore the disconnect and let the built-in reconnect code handle it. I believe that my problem was that I had looked at examples of pre-V3 code and didn't understand that it was handled differently in V3. So, a better disconnect event handler would be
socket.on("disconnect", (reason) => {
console_log("disconnect due to " + reason);
if (reason === "io server disconnect") {
// disconnect initiated by server. Manually reconnect
socket.connect();
}
});

socket.io force disconnect client

I may be doing something wrong here but I can't get my head around this.
The following does not work:
client
$("#disconnectButton").click(function() {
socket.emit("disconnect");
});
server
socket.on("disconnect", function() {
console.log("this never gets called");
});
Can't I manually call the disconnect event from the client side? Because the following works:
client
$("#disconnectButton").click(function() {
socket.emit("whatever");
});
server
socket.on("whatever", function() {
socket.disconnect();
console.log("this gets called and disconnects the client");
});
'disconnect' event is Socket.io event,if you use emit to call the 'disconnect',may be cause other problom
so:
$("#disconnectButton").click(function() {
socket.emit("disconnect");
});
replace:
$("#disconnectButton").click(function() {
socket.disconnect();
});
For now, socket.emit('disconnect') or socket.disconnect() doesn't work.
The correct syntax to disconnect to the socket server is
socket.close()

Test the functionality of keepalive in a Node.js TCP socket

I've been testing the functionality of keepalive in Node.js TCP sockets. It seems that I'm missing something here!
Here is my server code:
var net = require('net');
function accept(socket) {
socket.setKeepAlive(false);
socket.on('data', function(data) {
console.log("DATA");
console.log(data);
});
socket.on('error', function (e) {
console.log("ERROR");
console.log(e);
});
socket.on('close', function () {
console.log("CLOSE");
});
socket.on('end', function () {
console.log("END");
});
socket.write("Hi");
}
var server = net.createServer(accept);
server.listen(8011);
And it is my client code:
var net = require('net');
var socket = new net.Socket();
socket.setKeepAlive(false);
socket.on('data', function(data) {
console.log("DATA");
socket.write(data);
});
socket.on('error', function (e) {
console.log("ERROR");
console.log(e);
});
socket.on('close', function () {
console.log("CLOSE");
});
socket.on('end', function () {
console.log("END");
});
socket.connect(8011, '127.0.0.1');
Why does the server (or the client) not close the connection even if no data has been sent or received for a long time (120 sec)?
I'm using Node.js version 0.10.5!
Because keep-alive works at a lower level. It sends a check packet without any data payload and if there's no answer, then the connection is considered broken.
Try doing the same, but unplug your Ethernet cable from one of the machines.
Edit 0:
Sorry, misread your code a bit.
TCP keep-alive feature is often called "dead peer detection". Read about its mechanics, for example, here. With keep-alive disabled there's nothing in TCP itself that would force the connection to be closed after any inactivity timeout. It's intermediate devices like NAT-ing routers that may expire state and break your connection, not the communicating ends themselves.

Node.js: client doesn't die when TCP connection closes

I built a simple TCP server and a simple TCP client in Node.js
Now, when the client sends "exit" to the server, the connection is successfully closed. The server deletes the socket from its sockets list and sends "Bye bye!" to the client.
The connection on the client is closed as well but the app is still waiting for other inputs, so it doesn't die and I'm forced to type CTRL+C.
I tried adding process.exit() after connection closes but it doesn't work:
CLIENT CODE:
var net = require('net'),
config = require(__dirname + '/config.json'),
connection = net.createConnection(config.port, config.host);
connection.setEncoding('utf8');
connection.on('connect', function () {
console.log('Connected');
});
connection.on('error', function (err) {
console.error(err);
});
connection.on('data', function (data) {
console.log('ยป ' + data);
});
connection.on('close', function() {
console.log('Connection closed');
});
process.stdin.on('data', function (data) {
if ((new String(data)).toLowerCase() === 'exit') {
connection.end();
process.exit();
}
else {
connection.write(data);
}
});
process.stdin.resume();
SERVER CODE:
var server = require('net').createServer(),
config = require(__dirname + '/config.json'),
sockets = [];
server.on('connection', function (socket) {
socket.setEncoding('UTF-8');
socket.on('data', function (data) {
console.log('Received data: ' + data);
if (data.trim().toLowerCase() === 'exit') {
socket.write("Bye bye!\n");
socket.end();
}
else {
sockets.forEach(function (client) {
if (client && client != socket) {
client.write(data);
}
});
}
});
socket.on('close', function () {
console.log('Connection closed');
sockets.splice(sockets.indexOf(socket), 1);
console.info('Sockets connected: ' + sockets.length);
});
sockets.push(socket);
});
server.on('listening', function () {
console.log('Server listening');
});
server.on('close', function () {
console.log('Server is now closed');
});
server.on('error', function (err) {
console.log('error:', err);
});
server.listen(config.port);
EDIT:
I added a client connection "on close" event handler. So, the string "Connection closed" is now printed by the server and by the client too.
I think you're looking for this: socket.unref().
From Node.js documentation (https://nodejs.org/api/net.html#net_socket_unref):
socket.unref()#
Calling unref on a socket will allow the program to exit if this is the only active socket in the event system. If the socket is already unrefd calling unref again will have no effect.
Some time ago when improving the tests suite for node-cubrid module, I had encountered the same problem. After all tests have passed, nodeunit process didn't quit because node-cubrid was using connection.end() to close the client socket when timeout occurs, just like you did.
Then I replaced connection.end() with connection.destroy(), a cleaner way to ensure the socket is really closed without actually terminating the running process, which, I think, is a better solution than the above suggested process.exit(). So, in your client code context, I would do:
process.stdin.on('data', function (data) {
if ((new String(data)).toLowerCase() === 'exit') {
connection.destroy();
}
else {
connection.write(data);
}
});
According to Node.js documentation:
socket.destroy()
Ensures that no more I/O activity happens on this socket. Only necessary in case of errors (parse error or so).
I doubt that if ((new String(data)).toLowerCase() === 'exit') is succeeding because data most likely has a trailing newline (in your server, you trim() before doing the comparison, but not in the client).
If that's fixed, you've got a logic problem: when getting "exit" you close the connection without sending "exit" to the server, so the server code that looks for "exit" will never execute.
You have to put the process.exit() instruction only on the last event handler. So, in this case you have to put it inside the client connection "on close" event handler:
CLIENT:
connection.on('close', function() {
console.log('Connection closed');
process.exit();
});
Try with Event: 'close' in the server:
http://nodejs.org/api/net.html#net_event_close

Node.js and Socket.IO - How to reconnect as soon as disconnect happens

I'm building a small prototype with node.js and socket.io. Everything is working well, the only issue I'm facing is that my node.js connection will disconnect and I'm forced to refresh the page in order to get the connection up and running again.
Is there a way to reestablish the connection as soon as the disconnect event is fired?
From what I've heard, this is a common issue. So, I'm looking for a best-practice approach to solving this problem :)
Thanks very much,
Dan
EDIT: socket.io now has built-in reconnection support. Use that.
e.g. (these are the defaults):
io.connect('http://localhost', {
'reconnection': true,
'reconnectionDelay': 500,
'reconnectionAttempts': 10
});
This is what I did:
socket.on('disconnect', function () {
console.log('reconnecting...')
socket.connect()
})
socket.on('connect_failed', function () {
console.log('connection failed. reconnecting...')
socket.connect()
})
It seems to work pretty well, though I've only tested it on the websocket transport.
edit: Socket.io has builtin-support now
When I used socket.io the disconnect did not happen(only when i closed the server manually). But you could just reconnect after say for example 10 seconds on failure or something on disconnect event.
socket.on('disconnect', function(){
// reconnect
});
I came up with the following implementation:
client-side javascript
var connected = false;
const RETRY_INTERVAL = 10000;
var timeout;
socket.on('connect', function() {
connected = true;
clearTimeout(timeout);
socket.send({'subscribe': 'schaftenaar'});
content.html("<b>Connected to server.</b>");
});
socket.on('disconnect', function() {
connected = false;
console.log('disconnected');
content.html("<b>Disconnected! Trying to automatically to reconnect in " +
RETRY_INTERVAL/1000 + " seconds.</b>");
retryConnectOnFailure(RETRY_INTERVAL);
});
var retryConnectOnFailure = function(retryInMilliseconds) {
setTimeout(function() {
if (!connected) {
$.get('/ping', function(data) {
connected = true;
window.location.href = unescape(window.location.pathname);
});
retryConnectOnFailure(retryInMilliseconds);
}
}, retryInMilliseconds);
}
// start connection
socket.connect();
retryConnectOnFailure(RETRY_INTERVAL);
serverside(node.js):
// express route to ping server.
app.get('/ping', function(req, res) {
res.send('pong');
});
Start reconnecting even if the first attempt fails
If the first connection attempt fails, socket.io 0.9.16 doesn't try to reconnect for some reason. This is how I worked around that.
//if this fails, socket.io gives up
var socket = io.connect();
//tell socket.io to never give up :)
socket.on('error', function(){
socket.socket.reconnect();
});
I know this has an accepted answer, but I searched forever to find what I was looking for and thought this may help out others.
If you want to let your client attempt to reconnect for infinity (I needed this for a project where few clients would be connected, but I needed them to always reconnect if I took the server down).
var max_socket_reconnects = 6;
var socket = io.connect('http://foo.bar',{
'max reconnection attempts' : max_socket_reconnects
});
socket.on("reconnecting", function(delay, attempt) {
if (attempt === max_socket_reconnects) {
setTimeout(function(){ socket.socket.reconnect(); }, 5000);
return console.log("Failed to reconnect. Lets try that again in 5 seconds.");
}
});

Resources