Ws: Constantly crashing when sending. Error not opened

Created on 26 Jul 2014  路  14Comments  路  Source: websockets/ws

I'm suspecting it's because client is trying to send to a dead socket.
Any other way to handle this?

My scenario is mobile App -> browser. App gets disconnect event too late, so it keeps sending packets while the browser is already disconnected.

Here's my test code:

var Client = [];
function findClient(url) {
return (Client.indexOf(url));
}


wss.on('connection', function(ws) {
    Client.push(ws);
    console.log('Connected: %s', ws.upgradeReq.url);
    console.log('Clients: %s', Client.length);

ws.on('message', function(message, flags) {

    for( var i = 0; i < Client.length; i++) {
         Client[i].send(message, function(error) {
         if(error != null) {
         console.log('error: %s', error);
         ws.close();
         ws._socket.destroy();
         Client.splice(findClient(ws.upgradeReq.url));
}
});

ws.on('close', function(user) {
    console.log('Disconnected: %s', ws.upgradeReq.url);
    ws.close();
    ws._socket.destroy();
    Client.splice(findClient(ws.upgradeReq.url));
    console.log('Clients: %s', Client.length);



  });
       ws.on('error', function(error) {
        if(error != null) {
         console.log('error: %s', error);
         ws.close();
         ws._socket.destroy();
         Client.splice(findClient(ws.upgradeReq.url));
    }
  });

    ws.on('close', function(user) {
    console.log('Disconnected: %s', ws.upgradeReq.url);
    ws.close();
    ws._socket.destroy();
    Client.splice(findClient(ws.upgradeReq.url));
    console.log('Clients: %s', Client.length);

  });

Any help appreciated :)

Most helpful comment

The second parameter for the send method is an error handler. Do something like this where you're sending messages:

ws.send(message, function(error) {
    // Do something in here here to clean things up (or don't do anything at all)
});

All 14 comments

more important, why does the socket die? And can it be revived rather than crashing

the browser gets disconnected. at the same time the disconnect event is sent to mobile, but because of latency, internet connectivity speed, etc, etc, it get's it very late. so it keeps sending packages to the browser, which is already disconnected. sorry for my english.

Got the same error:

 /home/ubuntu/www/idg_v2/production/releases/20140907092659/node_modules/racer-highway/node_modules/ws/lib/WebSocket.js:181
    else throw new Error('not opened');
               ^
Error: not opened
  at WebSocket.send (/home/ubuntu/www/idg_v2/production/releases/20140907092659/node_modules/racer-highway/node_modules/ws/lib/WebSocket.js:181:16)

I think we should n't kill the app if the error happened!

Same thing was happening to me. I added a condition on my clients[i].send() event to make sure the socket's open before attempting a send, and it fixed my problem:

var length = this.clients.length;
for(var i = 0; i < length; i++){
    if(this.clients[i].readyState != this.clients[0].OPEN){
        console.error('Client state is ' + this.clients[i].readyState);
    }
    else{
        this.clients[i].send(data);
    }
}

I've seen this problem come up for about 99% of the people starting to use this library.

Interesting to note that the WHATWG spec for HTML WebSockets only talks about throwing an error when the socket is in CONNECTING state.

https://html.spec.whatwg.org/multipage/comms.html#dom-websocket-send

The send(data) method transmits data using the connection. If the readyState attribute is CONNECTING, it must throw an InvalidStateError exception. Otherwise, the user agent must run the appropriate set of steps from the following list: [...]

Imo, throwing an error is a good for browser but it's absolutely bad practice for server.

My opinion is that send is inherently asynchronous and it should be left for the callback to handle errors (if needed).

+1

The second parameter for the send method is an error handler. Do something like this where you're sending messages:

ws.send(message, function(error) {
    // Do something in here here to clean things up (or don't do anything at all)
});

Add a listener for the error event to handle these cases or use a callback as suggested by @GeekLad.

@lpinca adding a listener won't solve the problem. The only way is use the callback, or add a try/catch statement around send():

// from lib/WebSocket.js
if (this.readyState !== WebSocket.OPEN) {
  if (cb) cb(new Error('not opened'));
  else throw new Error('not opened');
  return;
}

I open a PR to fix/add this feature: https://github.com/websockets/ws/pull/1300

for me this error handling worked:
setInterval(()=>{ try { if (ws.readyState != WebSocket.CLOSED) { ws.send(${new Date()});} } catch(e) {console.log(e);} });

that

for me this error handling worked:
setInterval(()=>{ try { if (ws.readyState != WebSocket.CLOSED) { ws.send(${new Date()});} } catch(e) {console.log(e);} });

that worked for me !

Was this page helpful?
0 / 5 - 0 ratings

Related issues

quesurifn picture quesurifn  路  3Comments

robertmylne picture robertmylne  路  3Comments

HanHtoonAung picture HanHtoonAung  路  3Comments

Globik picture Globik  路  3Comments

nodesocket picture nodesocket  路  4Comments