简体   繁体   中英

NodeJS Websocket how to reconnect when server restarts

In Node.js I'm using websockets/ws for a WebSocket connection. Below is the code for the client. Let's say the server socket we are connecting to goes down for a minute. The close event will fire, but what is the best way to reconnect to the socket whenever the socket on the server goes down or errors?

var ws = new WebSocket('ws://localhost');

ws.on('open', function() {
    console.log('socket open');
});
ws.on('error', function() {
    console.log('socket error');
    // how do I reconnect to the ws after x minutes here?
});
ws.on('close', function() {
    console.log('socket close');
    // how do I reconnect to the ws after x minutes here?
});

Try this:

var reconnectInterval = x * 1000 * 60;
var ws;
var connect = function(){
    ws = new WebSocket('ws://localhost');
    ws.on('open', function() {
        console.log('socket open');
    });
    ws.on('error', function() {
        console.log('socket error');
    });
    ws.on('close', function() {
        console.log('socket close');
        setTimeout(connect, reconnectInterval);
    });
};
connect();

You get to use the original implementation without having to wrap it.

I've used https://github.com/joewalnes/reconnecting-websocket/blob/master/reconnecting-websocket.js with success.

You should be able to do:

ws = new ReconnectingWebSocket('ws://....');
ws.reconnectInterval = 60000; // try to reconnect after 10 seconds

2018-Jan update

Reconnecting to a disconnected web socket is non-trivial, and best delegated to a library . The smallest and most actively maintained library for this purpose at the moment is reconnecting-websocket , which obsoletes joewalnes's library from the other answer. For Node.js specifically, you need to pass a constructor, such as WebSocket:

import WebSocket from 'ws';
import ReconnectingWebSocket from 'reconnecting-websocket';
const ws = new ReconnectingWebSocket('wss://some-feed.com', [], {
  constructor: WebSocket,
  connectionTimeout: ...,  // in milliseconds
  reconnectInterval: ...,
});

using async-await if Socket closed or any error occurred on the server the client will try to connect automatically every 5 sec forever

const ws = require('ws')
let openedSocketFlag = null
const timeInterval = 5000
const port = 3000
const url = `ws://localhost:${port}`

function connect() {
  const client = new ws(url)
  return new Promise((resolve, reject) => {
    console.log('client try to connect...')

    client.on('open', () => {
      console.log('WEBSOCKET_OPEN: client connected to server at port %s', port)
      openedSocketFlag = true
      resolve(openedSocketFlag)
    })

    client.on('message', (data) => {
      console.log(data.toString())
    })

    client.on('close', (err) => {
      console.log('WEBSOCKET_CLOSE: connection closed %o', err)
      openedSocketFlag = false
      reject(err)
    })

    client.on('error', (err) => {
      console.log('WEBSOCKET_ERROR: Error', new Error(err.message))
      openedSocketFlag = false
      reject(err)
    })
  })
}

async function reconnect() {
  try {
    await connect()
  } catch (err) {
    console.log('WEBSOCKET_RECONNECT: Error', new Error(err).message)
  }
}

reconnect()

// repeat every 5 seconds
setInterval(() => {
  if (!openedSocketFlag) {
    reconnect()
  }
}, timeInterval)

After examining @Mohamed Farouk's answer, I believe that there is merit in using a promise to signify the status of the connection. Here's an example that takes a bit from that answer, and a bit from my original:

const address = "ws://localhost";
const reconnectInterval = x * 1000 * 60;
const ws = {};
const establishSocket = address => new Promise((resolve, reject)=>{
  const s = new WebSocket(address);
  s.on("open", ()=>{
    delete ws.reason;
    ws.socket = s;
    console.log('socket open');
  });
  s.on("error", ()=>console.log('socket error'));
  s.on("close", reject);
}).catch(async (reason)=>{
  ws.socket = null;
  ws.reason = reason;
  console.log('socket close');
  await new Promise(resolve=>setTimeout(resolve, reconnectInterval));
  establishSocket(address);
});
establishSocket(address);

I make no assertions as to which approach is better -- I just thought this was an interesting solution.

You should consider a migration to socket.io .

  1. It has built-in auto-reconnect functionality . And you don't have to do anything for it. It is already enabled by default.
  2. Surprisingly, it is compatible with older browsers, even browsers that don't support native websockets.

The code of both is very similar, but the socket.io is perhaps just a little shorter. eg for the server code we used to write something like this:

const WebSocketServer = require('websocket').server
const ws = new WebSocketServer({ httpServer });
ws.on('request', (request) => onConnection(request));

function onConnectionRequest(request) {
  const connection = request.accept(null, request.origin);
  if (!connection) return;
  connection.on('message', (msg) => onMessageReceived(msg));
  connection.on('close', () => onConnectionClosed());
}

function onMessage(message) {
  if (message.type === 'utf8') {
    const data = message.utf8Data;
    const request = JSON.parse(data);
    // todo use request
  }
}

Socket.io code is very similar, but just a little shorter.

const io = require('socket.io')(httpServer);
io.on('connection', (socket) => onConnection(socket));

function onConnection(socket) {
  socket.on('message', (msg) => onMessage(msg));
  socket.on('disconnect', (reason) => onDisconnect(reason));
}

function onMessage(request) {
  // todo use request
}

However, do take in mind, that you also have to rewrite the client code. eg For Angular I use the ngx-socket-io plugin, which simplifies the code extremely.

i am using 'websocket' in my client side react/nextjs , and here is the urls for the specific package : https://www.npmjs.com/package/websocket
https://github.com/theturtle32/WebSocket-Node

and i am using 'reconnecting-websocket' package to reconnect the client websocket to the server (which is Django channels) when the server is restarted . and here is the official package url :
https://www.npmjs.com/package/reconnecting-websocket

and here is a simple example usage :

import { w3cwebsocket as W3CWebSocket } from "websocket";
import ReconnectingWebSocket from 'reconnecting-websocket';


//inside react component - nextjs page :

const options = {
    WebSocket: W3CWebSocket, // custom WebSocket constructor
    connectionTimeout: 1000,
    maxRetries: 10,
};



const isServerSide = typeof window === "undefined";
let client
if(!isServerSide) {
    client = new ReconnectingWebSocket(`ws://127.0.0.1:8000/ws/`,[], options);
    client.binaryType = "arraybuffer";
}


useEffect(() => {
    client.onopen = () => {
        console.log('WebSocket Client Connected');
    };
    client.onerror = (error)  => {
        console.log("Connection Error: " , error);
    };

    client.onclose = (close) => {
        console.log('echo-protocol Client Closed', close);
    };

}, [])

this is just example and change it based on your case/requirements.
i hope this helpful

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM