52

I've been searching for a solution to the "WebSocket is already in CLOSING or CLOSED state" error message and found this:

  1. Meteor WebSocket is already in CLOSING or CLOSED state error
  2. WebSocket is already in CLOSING or CLOSED state.

Answer #1 is for strictly related to Meteor and #2 has no answers... I have a Node server app with a socket:

const WebSocket = require('ws');
const wss = new WebSocket.Server({ server });

wss.on('connection', function connection(socket) {
  socket.on('message', function incoming(data) {
    console.log('Incoming data ', data);
  });
});

And clients connect like this:

const socket = new WebSocket('ws://localhost:3090'); //Create WebSocket connection

//Connection opened
socket.addEventListener('open', function(event) {
  console.log("Connected to server");
});

//Listen to messages
socket.addEventListener('message', function(event) {
  console.log('Message from server ', event);
});

However after a few minutes, clients randomly disconnect and the function

socket.send(JSON.stringify(data));

Will then throw a "WebSocket is already in CLOSING or CLOSED state.".

I am looking for a way to detect and deal with these disconnections and immediately connect again.

What is the most efficient way to do this?

adelriosantiago
  • 7,762
  • 7
  • 38
  • 71
  • Possible duplicate of [How to clear buffer on websocket?](https://stackoverflow.com/questions/47897486/how-to-clear-buffer-on-websocket) – Myst Jan 27 '18 at 07:03
  • 1
    You can find the answer [here](https://stackoverflow.com/questions/47897486/how-to-clear-buffer-on-websocket/47898118#47898118) – Myst Jan 27 '18 at 07:03
  • This is a known issue and problem that has affected a lot of people. This may help: https://stackoverflow.com/a/53843646/468592 – Jeremy Harris Dec 22 '18 at 17:54
  • 2
    @JeremyHarris link is broken – temirbek Nov 09 '21 at 09:41
  • It's not technically broken. Looks like the original answer author deleted the answer. If you have high enough reputation you can see the deleted answer. Appears there is a valid answer here anyway. – Jeremy Harris Nov 15 '21 at 14:53

3 Answers3

32

The easiest way is to check if the socket is open or not before sending.

For example - write a simple function:

function isOpen(ws) { return ws.readyState === ws.OPEN }

Then - before any socket.send make sure it is open:

if (!isOpen(socket)) return;
socket.send(JSON.stringify(data));

You can also rewrite the send function like this answer but in my way you can log this situations.

And, for your second request

immediately attempt to connect again

There is no way you can do it from the server.

The client code should monitor the WebSocket state and apply reconnect method based on your needs.

For example - check this VueJS library that do it nicely. Look at Enable ws reconnect automatically section

yeya
  • 1,968
  • 1
  • 21
  • 31
0

Well, my answer is simple, is just you send message to the web socket in an interval of time, to understand that you are using the service. It is better than you got another connection. Now, you start your project where are the web socket function and inspect elements to see the state Time, and see the time that change of "pending" for the time when closes. So now you will define a media of interval to make a setInterval functions like this for example: enter code here

const conn = WebSocket("WSS://YourLocationWebSocket.com");
setInterval(function(){
  var object = {"message":"ARandonMessage"};
  object = JSON.stringify(object);
  conn.send(object);
},/*The time, I suggest 40 seconds, so*/ 40000)
Emanoel José
  • 125
  • 1
  • 6
0

might be late to the party, but i recently encountered this problem & figured that the reason is because the readystate property of the websocket connection is 3 (CLOSING) https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/readyState at the time the message was sent.

i resolved this by checking the readystate property; if it equals to 3, close and reinitialize the websocket connection. then do a while loop that exits when the readystate property equals to 1, otherwise a delay, to ensure that the new connection is already open.

   if ( this.ws.readyState === 3 ) {
        this.ws.close();
        this.ws = new WebSocket(`wss://...`);

        // wait until new connection is open
        while (this.ws.readyState !== 1) {
          await new Promise(r => setTimeout(r, 250));
        }
   }

   this.ws.send(...)