I have a socket.io node script with:
socket.on('disconnect', function(data) {
console.log('disconnect!');
});
When I connect with Chrome / Safari and close the page, I see 'disconnect!' in my server console.
However, when I connect with my iPhone and close the page, I don't see this message. I see debug - xhr-polling closed due to exceeded duration
How do I receive the disconnect event with iOS?
Socket.io switches to the xhr-polling transport when you are viewing the page in your iPhone. This might be caused by the configuration of socket.io or because the browser in your iPhone does not (fully) support websockets.
The xhr-polling implementation in socket.io does not emit disconnect event when the connection is closed, see github issue #431. You can reproduce this issue in your Chrome browser by forcing the socket.io server to use the xhr-polling transport only:
// the server side
var io = require('socket.io').listen(httpServer);
io.set('transports', ['xhr-polling']);
Good news: you can ask socket.io's client to notify the server about disconnect by turning on the sync disconnect on unload flag:
// the browser (HTML) side
var socket = io.connect('http://localhost', {
'sync disconnect on unload': true
});
Warning: this option can worsen the user experience when the network and/or your server are slow, see this pull request for more information.
UPDATE
According to socket.io force a disconnect over XHR-polling, setting sync disconnect on unload might not be enough to fix the problem on iPhone/iPad.
As you can see in socket.io-client source code, sync disconnect on unload sets up a listener for beforeunload event, which is not supported by iOS Safari according.
The solution is probably to fix socket.io-client to listen for both unload and pagehide events, because
the unload event may not work as expected for back and forward optimization. Use the pageshow and pagehide events instead. [Apple Web Content Guide].
Related
I have built websocket client in node js. I need to restart it after every 8-10 days. It suddenly stops listening to the websocket server. I have used the following lib for connection.
"ws": "^6.2.1"
I do restart connection and print logs in onclose and onerror listeners.
this.connection.onerror = error => {
rawDataStreamLog.info("Websocket ::: onerror " + JSON.stringify(error))
this.restartConnection();
};
this.connection.onclose = () => {
rawDataStreamLog.info("Websocket ::: onclose")
this.restartConnection()
};
Any insight would be greatly appreciated. Thanks.
It's very likely your server initiated the disconnection. Or maybe something went wrong with the network connection.
It has been my experience that websocket client code for long-lived connections should detect and handle close events by reconnecting. If things still fail after several attempts to reconnect you can investigate what's wrong at the server or in the network.
Does your server send websocket ping (keepalive) messages? If not, it should.
So, I am still in the experimental phase of Socket.io, but I just can't figure out why my code is doing this. So, I have the code below and when I console.log the code, it repeats the the connection even when there is only one connection. Do you know a solution?
io.on('connnection', (socket) => {
console.log("A new user is connected.")
})
Client side:
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io()
</script>
Node.js Console:
A new user is connected.
A new user is connected.
A new user is connected.
A new user is connected.
A new user is connected.
A new user is connected.
A new user is connected.
...
(Note: there is only one connection, and I have already cleared the browser cashe)
Here are some of the possible reasons for socket.io connecting over and over:
Your socket.io client and server versions do not match and this causes a connection failure and an immediate retry.
You are running with some infrastructure (like a proxy or load balancer) that is not configured properly to allow lasting webSocket connections.
You are running a clustered server without sticky webSocket connections.
You have put the server-side io.on('connnection', ...) code inside some other function that is called more than once causing you to register multiple event handlers for the same event so you think you're getting multiple events, but actually you just have multiple listeners for the one occurrence of the event.
Your client code is calling its var socket = io() more than once.
Your client page is reloading (and thus restarting the connection on each reload) either because of a form post or for some other reason.
FYI, you can sometimes learn something useful by installing listeners for all the possible error-related events on both client and server connections and then logging which ones occur and any parameters that they offer. You can see all the client-related error events you can listen to and log here.
To solve repetion problem write your code like that for socket:
io.off("connnection").on('connnection', (socket) => {
console.log("A new user is connected.")
})
My browser is defaulting to "polling" method, causing me not to get the disconnect event on the server side.
I've tried the solution covered in socket.io force a disconnect over XHR-polling but this didn't do the trick for me:
Server.socket = io.connect("https://somedomain:8443", {"sync disconnect on unload":true, secure:true});
How can I track users leaving my server with polling?
so, apparently for some reason the heartbeat timeout was too long for me to think the disconnect mechanism was working.
I changed the timings:
var io = require('socket.io')(server, {'pingInterval': 4000, 'pingTimeout': 8000});
In the server, and after 8 seconds, sure thing, I get the disconnect event.
The low numbers are because I'm creating a multiplayer game...
Trying to use socket.io-client to connect to a websocket server that is written in Go. I've successfully connected using the node WebSocket library (npm). So the working Websocket code looks like:
goSocketPort = 6060
url = "ws://localhost:#{goSocketPort}/streamresults/"
ws = new WebSocket(url)
ws.on('open', ->
log "socket opened"
)
ws.on('message', (message) ->
console.log('received: %s', message)
#log "Socket message: #{JSON.stringify message}"
)
Pretty easy and it works -- the socket on the other end sends messages on a set frequency. But I initially tried with socket.io-client (npm) and just couldn't get it to go. It certainly lists websocket as its first-preference transport, but damn if I can get it to connect:
socket = ioClient.connect("#{url}", {port: goSocketPort, transports: ['xhr-polling', 'websocket']})
socket.on("connect", (r) ->
log "connected to #{url}"
)
The connection never happens, so none of the on events are fired and the code exits right away. I've tried: leaving the port off the url and adding it in the options, leaving off the transports option (which means "all" according to the docs) and using an http url. Is socket-io.client not capable of connecting to a "standard" websocket?
Based on our chat, it looks like you were misled by this quote:
The socket.io client is basically a simple HTTP Socket interface implementation. It looks similar to WebSocket while providing additional features and leveraging other transports when WebSocket is not supported by the user's browser.
What this means is that it looks similar to WebSocket from the perspective of client/server code that interacts with the Socket.io client/server. However, the network traffic looks very different from a simple WebSocket - there's an initial handshake in addition to a more robust protocol built on top of WebSocket once that's connected. The handshake is described here and the message protocol here (both are links to the Socket.IO protocol spec).
If you're writing a WebSocket server, you're better off just using the bare WebSocket interface rather than the Socket.io client, unless you intend to implement all of the Socket.io protocol.
Not sure if this was the case at the time, but socket.io's website now states this directly in the docs.
Although Socket.IO indeed uses WebSocket as a transport when possible,
it adds additional metadata to each packet. That is why a WebSocket
client will not be able to successfully connect to a Socket.IO server,
and a Socket.IO client will not be able to connect to a plain
WebSocket server either.
https://socket.io/docs/
I have a socket.io connection using xhr as its only transport. When I load up the app in the browser (tested in chrome and ff), the socket connects and everything works well until I navigate away from the page. If I reload the browser, I can see the 'disconnect' event get sent out by the client, but the server disconnect event doesn't fire for a very long time (presumably when the client heartbeat times out). This is a problem because I do some cleanup work in the server when the client disconnects. If the client reloads, I get multiple connection events before disconnect is fired. I've tried manually emitting a disconnect message from the client in the window's 'beforeunload' event as well, but to no avail. Any ideas?
I debugged the socket.io server, and I can confirm that Manager.prototype.onClientDisconnect is only getting hit for "close timeout" reasons.
After some more debugging, I noticed the following configuration in the socket.io Manager object:
blacklist : ['disconnect']
That causes this branch from namespace.js to not process the event:
case 'event':
// check if the emitted event is not blacklisted
if (-~manager.get('blacklist').indexOf(packet.name)) {
this.log.debug('ignoring blacklisted event `' + packet.name + '`');
} else {
var params = [packet.name].concat(packet.args);
if (dataAck) {
params.push(ack);
}
socket.$emit.apply(socket, params);
}
The change is detailed in this pull request https://github.com/LearnBoost/socket.io/pull/569. I understand why this is in place for XHR, since anyone could send an HTTP request with random session IDs trying to disconnect other users from the server.
What I plan to do instead is to check each new connection for an existing session id in the server, and make sure to run my disconnect logic before continuing with the connection logic.