Socket.io and modern browsers aren't working - node.js

I'm having some weird issues with socket.io and modern browsers. Surprisingly, with IE9 works fine because fallbacks to flashsocket which appears to work better.
In my server (with express)
var io = socketio.listen(server.listen(8080));
io.configure('production', function(){
console.log("Server in production mode");
io.enable('browser client minification'); // send minified client
io.enable('browser client etag'); // apply etag caching logic based on version number
io.enable('browser client gzip'); // gzip the file
io.set('log level', 1); // reduce logging
io.set('transports', [ // enable all transports (optional if you want flashsocket)
'websocket'
, 'flashsocket'
, 'htmlfile'
, 'xhr-polling'
, 'jsonp-polling'
]);
});
On the browser I can see in the Network tab (on Chrome) that a websocket is stablished and get in 101 Switching Protocols in Pending mode. After that, appears xhr-polling and jsonp-polling (what happend to flashsocket ? )
The worst part is that info don't go back and forth. I have this on connection:
io.sockets.on('connection', function (socket) {
// If someone new comes, it will notified of the current status of the application
console.log('Someone connected');
app.sendCurrentStatus(socket.id);
io.sockets.emit('currentStatus', {'connected': true);
});
And on client:
socket.on('currentStatus', function (data){ console.log(data) });
However I only be able to see that log when I turn off the server which is launched with:
NODE_ENV=production node server.js
What am I doing wrong?

Finally, after really banging my head against a wall, I decided to test in several environments to see if it was a Firewall issue since the machine is behind several ones.
It turned out that no one but me had the problem so I checked the Antivirus (Trend Micro) and after disabling, Chrome/Firefox were able to make their magic.
Moral of the story
Besides what it says here - Socket.IO and firewall software - whenever you face an issue that nobody in the internet seems to have (ie, not logged on github nor the socket.io group) it's probably caused by your Antivirus. They are evil. Sometimes.

You should just be having the socketio listen on the app itself.
Also, I have never need to do all of the server side configuration with the socket that you are doing - socket.io should work out of the box on most browsers without doing that. I would try first without configuring.
Also, on the server, you should emit from the socket that is passed to the callback function rather than doing io.sockets.on.
var io = socketio.listen(app);
io.sockets.on('connection', function (socket) {
// If someone new comes, it will notified of the current status of the application
console.log('Someone connected');
app.sendCurrentStatus(socket.id);
socket.emit('currentStatus', {'connected': true);
});
on the client, you need to connect first:
var socket = io.connect();
socket.on('currentStatus', function (data){ console.log(data) });
If you want to see an example of two way communication using socket.io, check out my Nodio application.
The server side:
https://github.com/oveddan/Nodio/blob/master/lib/Utils.js
And the client side:
https://github.com/oveddan/Nodio/blob/master/public/javascripts/Instruments.js

Related

Socket.IO on Heroku does NOT work without SSL

I have a chat server setup as such:
var port = Number(process.env.PORT || 5000);
var app = require('http').createServer(handler)
, io = require('socket.io').listen(app, {'log level':1, 'match origin protocol':true})
, fs = require('fs')
io.set('authorization', function (handshakeData, callback) {
console.log(handshakeData);
callback(null, true);
});
and then I handle some events:
io.sockets.on('connection', function(socket) {
socket.emit('handshaken', {id:socket.id}); // for HTML clients
socket.on('subscribe', function(roomId) {
doSubscribe(socket, roomId);
});
socket.on('unsubscribe', function(roomId) {
doUnsubscribe(socket, roomId);
});
socket.on('chat', function(data) {
doChat(data);
});
});
The client is on a different domain.
When I use the chat server via https, then everything is working fine. All the events are received. However, when I use http, I can see that the client can receive the 'handshaken' event, but nothing else is sent or received.
I wonder if this has anything to do with the socket.io authorization not working properly with non ssl connection.
However, in local environment, I can still use non ssl http://localhost:5000 as the chat server url without any issue. Is it also possible that this is an issue with Heroku?
UPDATE 1: After some investigation, if I use http url for the chat server, the server can emit to the client. The client can connect to the server, but cannot emit anything to the server (the server does not receive any emit).
Update 2: Some further investigations revealed that the chat server, under http, does received an emit, but only 1 emit. Any emit after that is not received.
It turned out that Sophos antivirus for Mac is the culprit here. After I disabled all web protection, my chat app works fine.
The interesting point here is that Sophos only targets Chrome browser, as Firefox and Safari work without any problem.

Adobe AIR- connection issues with socket.io

I have a desktop app in Adobe Air (flex).
I have used flashSocket.io library in my app to communicate with socket.io on node.js server.
It works perfectly for most of the clients.
But for some random client the flex app is not able to create a connection with the socket.io server. It constantly throws connection error and close error on flex. The clients are not behind any firewalls or proxy server.
The console has warning like
Web Socket Connection Invalid
I guess this for those clients who are not able to connect.
Since its working for majority of the users i don't know where should i look into. Also, i am unable to reproduce this on my side.
Here's the Server Code:
var io = require('socket.io').listen(app);
app.listen(8080, function() {
console.log('%s listening at %s', app.name, app.url);
});
io.configure(function() {
io.set('transports', ['flashsocket']);
io.set('flash policy port', 843);
});
Flex code:
socket = new FlashSocket("http://domain.com:8080/");
socket.addEventListener(FlashSocketEvent.CONNECT, onConnect);
socket.addEventListener(FlashSocketEvent.MESSAGE, onMessage);
socket.addEventListener(FlashSocketEvent.CLOSE, onDisconnect); //only close and connect_error event is always fired for certain clients
socket.addEventListener(FlashSocketEvent.CONNECT_ERROR, onConnectError);
Any help would be highly appreciated.
Use a different port, we're using 443.

socket.io example sometimes not connecting client side when using a reverse proxy

Using node-http-proxy, I've set up a reverse proxy for routing requests:
var httpProxy = require('http-proxy');
var server = httpProxy.createServer({
hostnameOnly: true,
router: {
'www.example.com': 'localhost:3002'
}
}).listen(80);
Now, when I run the first example on http://socket.io/#how-to-use, the socket is sometimes not connecting with the client. I created two files to test this: server.js and index.html. To start the node application, i run server.js.
server.js:
var app = require('http').createServer(handler)
, io = require('socket.io').listen(app)
, fs = require('fs')
app.listen(3002);
function handler (req, res) {
fs.readFile(__dirname + '/index.html',
function (err, data) {
if (err) {
res.writeHead(500);
return res.end('Error loading index.html');
}
res.writeHead(200);
res.end(data);
});
}
io.sockets.on('connection', function (socket) {
console.log("Socket connected");
});
index.html:
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io.connect();
setInterval(function() {
console.log(socket.socket.connected);
}, 1000)
</script>
When the client does not connect, after the socket connects with the server, I repeatedly get the following output with intervals of +/- 10 seconds:
debug - setting request GET /socket.io/1/xhr-polling/Cqcw5xUjQ-B-Hw3FGF7Y?t=1385128607702
debug - setting poll timeout
debug - discarding transport
debug - cleared heartbeat interval for client Cqcw5xUjQ-B-Hw3FGF7Y
Now, when I refresh the browser a few times, the socket always connects with the server (that is, it always logs "Socket connected"), but sometimes it does not connect client side: console.log(socket.socket.connected) sometimes repeatedly prints "false" after refreshing index.html, and after another page refresh, it may repeatedly print "true" or "false" again if the socket did not or did connect with the client.
The example does work client-side when I do not use the reverse proxy, so when I run server.js on port 80 on www.example.com. It would be great if someone could point me out what could be the cause of this problem. I am using node.js v0.8.23, socket.io version 0.9.14 and node-http-proxy version 0.10.1.
UPDATE
Probably, I am actually using node v0.10.21. I thought I was using v0.8.23 by switching the node version using nvm, but for some reason it keeps switching back to v0.10. It is a known issue that http-proxy does not support web sockets for node versions later than 0.8, so that may be the cause. I am using robertklep's solution until I find something better.
I think the issue might be that socket.io is initially trying to use WebSockets as a transport medium and when that doesn't work (I don't know if node-http-proxy can proxy WS connections), it falls back to a transport that does work (xhr-polling) but the client and/or server gets confused in the process.
Try disabling the websocket and flashsocket transports to see if that makes it more reliable:
io.set('transports', [ 'xhr-polling', 'jsonp-polling', 'htmlfile' ]);
(more info)
It really was the node version I was using. Node-http-proxy does not work for node version >0.8 (see Node http proxy with proxytable and websockets). I thought I was using v0.8.23 but I was actually using v0.10.21. By using n, I could get node working for v0.8.23 for sure, and now it seems to work. I highly recommend n for resetting the node version.

emitting data via socket on browser close /window close

I need to send data to nodejs server via socket.io when the user closes the browser tab .
I tried doing :
var data={};
window.onbeforeunload = function() {
// i have a object to be sent
data.data1='abcd';
data.data2=1234;
socket.emit("senddata",data);
}
This code works when the user navigates around clicking links on the site but doesnot work when the user closes the browser tab
I also tried configuring the socket io on server side as below .. thinking the error may be due to socket connection being closed before emitting data:
var io = require('socket.io').listen(app.listen(port));
io.configure(function () {
io.set('close timeout',12000);
});
It also didnt work most of the time.
I also tried this on client side:
var socket = require('socket.io').listen(80, {
"sync disconnect on unload":false
});
It also did not work
I had tried receiving data like this
var io = require('socket.io').listen(app.listen(port));
io.sockets.on('connection', function (socket) {
socket.on('senddata', function (data) {
// data processing
});
});
please ..help me with this problem..thanks in advance..
When user connects - register on server side the time it happened.
Socket.IO has heart beating and pinging functionality. So just subscribe to disconnect event on server side and once it happens - means client disconnected - and you have on server time when client had connection. So that way you have timespan of client session.
Do not trust client to tell you any time or important data, as client can simply 'lie' - which leads to hacks/cheats/bugs on your server-side.
There is no reliable way to send data just before disconnect from client-side at all. There is nothing in Socket.IO for that, nor in just one of transports (WebSockets). As well as there is too many different scenarios of disconnection (power off, force close, ethernet cable out, wifi lose, etc).

socket.io - works first time, not second time onwards

When I start my node.js server and client gets connected, I am able to send a request from client (socket.emit) and get a response (socket.on('rentsAround'....)). But when I connect 2nd time onwards, the client is able to send, but server can not send or emit. So I have to restart the server again. I understand that it is working as expected, but somehow my understanding is wrong somewhere... Would someone please point out.
client side:
========
var socket = new io.Socket();
socket = io.connect();
socket.on('rentsAround', function(data){
registration.handleRentsAround(data);
});
socket.on('locationDetailsRes', function(data){
registration.handleRentsAround(data);
});
socket.on('connect', function(data){
alert('inside connect on client side');
});
socket.on('disconnect', function(){
// do something, if you want to.
});
.............
socket.emit("searchRent", {"lat":lat, "lng":lng});
server side:
========
socket.sockets.on('connection', function(client){
client.on('searchRent', function(msg){
console.log('inside on connection');
// do something and reply back
client.emit('rentsAround',{"totalRents":docs.length, "rents":docs});
});
client.on('disconnect', function(){
sys.puts("client disconnect");
mongoose.disconnect();
});
Socket.io 0.7 onwards will try and reuse connections to the same host. In my experience I've found this behaviour can be a little flakey.
I can't tell from the small code sample you provided, but I suspect the problem is that the second call to connect() is trying to reuse the first (closed) connection.
The workaround is to pass the 'force new connection' option when you call connect(). Eg:
io.connect("http://localhost", {'force new connection': true});
Your second line discards the object created in the first line. Simply doing this should work:
var socket = io.connect();
The problem with first send and second fail could be due to browser/protocol. I have seen such behaviour with Internet Explorer and XHR transport, and also with Opera using JSONP.
If you are using IE, try switching to JSONP and it should work properly. This can be done on the server side, by supplying the transport list to configuration. Just make sure JSONP comes before XHR. Something like this:
sio.set('transports', [
'websocket'
, 'flashsocket'
, 'jsonp-polling'
, 'xhr-polling'
, 'htmlfile'
]);
As of socket.io 1.0, two settings control this behaviour:
"force new connection":true, on the client connect() call.
"cookie":false, on the server Server() constructor.
Apparently, both produce the exact same behaviour.
The second method is, as of today, undocumented. However, looking at the source code you can see that all options passed to socket.io Server() are passed to the internal Engine.io library Server() constructor, which lets you change any of the options there. These options are documented here:
https://github.com/LearnBoost/engine.io

Resources