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 :)
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 !
Most helpful comment
The second parameter for the send method is an error handler. Do something like this where you're sending messages: