Socket.io client ignoring port when namespace used [Bug?] - javascript

I have a simple node.js app with socket.io (1.3.5), taken from socket.io examples:
// Setup basic express server
var express = require('express');
var app = express();
var server = require('http').createServer(app);
var io = require('socket.io')(server);
var port = process.env.PORT || 3000;
server.listen(port, function () {
console.log('Server listening at port %d', port);
});
// Routing
app.use(express.static(__dirname + '/public'));
io.of('/admin').on('connection', function(socket){
//handle conection on /admin namespace
});
io.of('/user').on('connection', function(socket){
//handle conection on /user namespace
});
Now in my front-end I connect to these specific namespaces like so (again, taken from the example):
var admin_socket = io('/admin');
var user_socket = io('/user');
The app is running on port 3000 and the website is opened using URL localhost:3000.
When doing that I am getting CORS errors, it seems like Socket.io on client side is not auto-detecting the port number as soon as I start using namespaces (in firefox dev tools I can see requests going to localhost/ rather than localhost:3000/).
If on my server-side I don't use namespaces:
io.on('connection', function(socket){
//handle general conection
});
And on front-end I connect this way:
var socket = io();
Everything works fine, port auto-discovery works and in firefox dev tools I can see connections being made to localhost:3000/.
Alternatively, if I still use namespaces on my back-end, and on front end I connect like so:
var admin_socket = io('localhost:3000/admin');
var user_socket = io(':3000/user'); //I can skip localhost
Again everything works (and indeed in firefox dev tools I can see network requests going to localhost:3000/).
How come the port auto-discovery is not working with namespaces? Is there a way to get it to work? Am I missing something here? Thanks.
See my answer below for a fix...

Ok so I did some debugging of code in socket.io.js and realized there is a potential bug there. On line 1050 a loc.hostname is used instead of loc.host.
This causes a hostname to be used when passing in a namespace, this doesn't include port number.
In case of no namespace being used, on line 1024 loc.host is being used and everything is fine.
I have taken a copy of the file and changed line 1050 to use host and everything works fine.
Found github issue with that, it is fixed in 1.4.x:
https://github.com/Automattic/socket.io-client/issues/812

No need to mess with ports, it pretty much should work just by
var admin_socket = io('/admin');
var user_socket = io('/user');

I don't think there is any way to get the auto port discovery to work without modifying the actual Socket.io code or waiting for a fix. The simplest thing you could do is just insert the current location.port including a colon before your namespace.
var admin_socket = io(':' + location.port + '/admin');
var user_socket = io(':' + location.port + '/user');
Or create a new function that will create a socket for you.
function sio(nsp) {
return io(':' + location.port + nsp);
}

Related

What do I replace "http://localhost:3000" with when using a server and not local machine?

I've been doing a lot of online courses with node and express. I want to get sockets.io to work but I can't even establish a connection at the moment. I am using a cPanel virtual private server and running code in the server terminal and then trying to use a website hosted on the server to access the .js file running on the server.
I've tried all sorts of different things but I'm reducing it to its most basic level to try get a connection. All the videos I've seen are running on a local machine and using the command prompt on a local machine to run the .js file and the browser to access http://localhost:3000.
The .js file I'm running on my cPanel server looks like this;
var express = require('express');
var app = express();
app.get('/', function(req,res){
res.send('Hello world 2');
})
app.listen(3000);
So how do I then access that via the browser? I have tried http://mywebsite.com:3000 and http://11.22.33.444:3000 if 11.22.33.444 is the server ip, but the browser just times out and there is no output in the server console.
ultimately I need to run a socket.io command that looks like this;
var socket = io.connect('http://localhost:3000');
and in all the tutorials I've seen they use this localhost:3000 but no one explains how to access this if its on an actual server so I'm pretty lost.
There are other examples like;
...
const http = require('http').createServer();
...
http.listen(3000 => () => {
console.log('listening on port 3000');
});
That's just a snippet of the code but I'm wondering how I then access that 3000 port from the browser without http://localhost:3000
IF you read the docs you will see that there is a guide how to connect it with express: https://socket.io/docs/
var app = require('express')();
var server = require('http').Server(app);
var io = require('socket.io')(server);
server.listen(3000);
// WARNING: app.listen(3000) will NOT work here!
app.get('/', function (req, res) {
res.status(200).json({ message: "Connected" });
});
io.on('connection', function (socket) {
console.log("somebody connected");
});
Think I just solved it. I tried a different port and it worked :/
No need to specify any address in io.connect()
const app = express();
const http = require('http').Server(app);
const io = require('socket.io')(http);
http.listen(process.env.PORT || 3000, function() {
});
<script src="/socket.io/socket.io.js"></script>
var socket = io.connect();

Socket.io - Multiple connections when there should only be one per browser window

I've noticed that when loading into my app it creates multiple socket connections.
This bug seems quite intermittent, I've been looking around for a solution but nothing seems to be working thus far.
Here's my server-side code:
var express = require('express');
var app = express();
var serv = require('http').Server(app);
var path = require('path');
app.get('/', function (req, res) {
res.sendFile(__dirname + '/client/index.html');
});
app.use('/client',express.static(__dirname + '/client'));
app.use(express.static(path.join(__dirname, 'skin')));
serv.listen(8081);
console.log("Server started");
var io = require('socket.io')(serv,{});
var socketCount = 0;
io.sockets.on('connection', function(socket){
console.log('Socket ' + socketCount + ' connected');
socketCount++;
socket.emit('socketConnected', true);
socket.on('disconnect',function(){
console.log('Socket ' + socketCount + ' disconnected');
socketCount--;
delete SOCKET_LIST[socket.id];
delete PLAYER_LIST[socket.id];
});
...
When refreshing the page, the disconnect function on the server fires, but only once despite the fact that there is supposedly several sockets. I then get multiple socket connecting, again.
When putting a breakpoint on the frontend (listening for socketConnected) it triggers multiple times. Can anyone point out any flaws in the code above that may cause this issue?
Thanks.
New development after some further debugging:
I've noticed that when I emit socketConnected as seen above, I have assumed that I am able to grab some further data from the frontend.
When sending data from the frontend back to the server again, I run my calculations on the server with it and then run a second socket.emit('something .. from the server to the frontend. - This takes several attempts before actually hitting a breakpoint on the frontend. During these attempts to emit the data from the server, this is where the several other connections are made.
However, if I wrap the second server emit in a setTimeout function it works fine and maintains the current connection without creating multiple more. Has anyone else encountered this issue? - If so, is there a solution that avoids using setTimeout?

How do I fix socketio spamming polling when I start my web app? [javascript, expressjs, socketio]

Here is the problem. When I load the page in the browser and check to see if my "test" was emitted, I run into this wall of spamming polling.
The code I use is exactly the same as in other projects I have done, so it makes no sense to me that this doesn't work now. -_-
app.js
var express = require('express');
var app = express();
var server = require('http').createServer(app);
var io = require('socket.io')(server);
var port = process.env.PORT || 8000;
server.listen(port, function(){
console.log('server ready - listening on *:8000');
});
app.get( '/*' , function( req, res, next ) {
//This is the current file they have requested
var file = req.params[0];
//Send the requesting client the file.
res.sendFile( __dirname + '/' + file );
});
io.on('connection', function (socket) {
socket.on('test', function(){
console.log("test worked");
});
});
client.js
var socket = io();
socket.emit("test");
I broke the code down to what you see above. There's nothing else. And it doesn't work. internal screaming
I'll post my comment as an answer so you can wrap up this question. One common reason that socket.io will loop with http requests and never successfully connect is if you are running mismatched version on the client and server. This seems to have happened recently with socket.io upon a recent version change so they must have made some change in how the connection logic works that makes it fail to connect if versions are mismatched.
If you load your client via this:
<script src="/socket.io/socket.io.js"></script>
Then, the client will always match the server version as long as you don't have any other <script> tags that are loading some other version of socket.io.
One more solution which worked for me ( Socket.IO 2.3.0 and Socket.IO Client 2.3.0 ) is to set the transports field when you create the instance of io on back-end and socket on front-end , like this :
On back-end :
io = require('socket.io')(http,{
log: false,
agent: false,
origins : '*:*' , // this is for the CORS browser error , I also use the cors npm module here
transports : [ 'websocket' ]
});
And on front-end :
const socket = socketIOClient(url,{
forceNew : false ,
secure : true ,
transports: [ 'websocket' ]
});
Hope it helps , if not the question owner , then maybe the others :)

Node.js application using Socket.io gives "Unexpected response code: 400" on OpenShift hosting

I've got a Node.js app that runs fine locally, but when I push it up to OpenShift it gives me this error in the dev console:
WebSocket connection to 'ws://myapp-mydomain.rhcloud.com/socket.io/?EIO=3&transport=websocket&sid=mpKjro8KjQ5dIg0GAAAE' failed: Error during WebSocket handshake: Unexpected response code: 400
It's a little multiplayer "game", you and any other players connected are cubes that can move around and can see each other's movement etc. I use Node and socket.io to get the player positions and send the new coordinates to other players, but when I host it on OpenShift it gives me the error above.
The weird thing is that it almost works i.e. you can see the other players move around, except it's very laggy and slow.
The same app worked fine on Scalingo hosting, so it must be an OpenShift thing.
This is my client side code for initiating socket.io:
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io();
</script>
And server:
var express = require('express');
var app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http);
app.get('/', function(req, res){
res.sendFile('index.html');
});
this.ipaddress = process.env.OPENSHIFT_NODEJS_IP;
this.port = process.env.OPENSHIFT_NODEJS_PORT || 8000;
http.listen( port, ipaddress, function(){
console.log('listening on:' + port);
});
Thank you apsillers, changing this line did the trick:
var socket = io();//OLD
var socket = new io("ws://myapp-mydomain.rhcloud.com:8000/"); //NEW
Still a 90ms delay, but that's an issue for another time. Also a bit annoying that I have to change it back if I want to run and test the app locally (which I do).

Node.js on multiple domains using express.vhosts()

I'm back here with a nodejs problem, I am writing a node server that allows two or more app.js running on the same system using express.vhost(). But I'm quite lost now.
The webhost server is a dedicated server running Ubuntu and plesk and I've assigned 2 ip's for different domains.
xxx.xxx.xxx.123 IP is assigned to domain-one.com
xxx.xxx.xxx.xxx.456 is assigned to domain-two.com
both run a nodejs server app.js
and are each allocated in /var/www/vhosts/[domain-name]/node/app.js
The server running the vhost is at /var/www/node/server.js here is the code
var express = require("express");
var app = express();
app
.use(express.vhost('domain-one.com', require('/var/www/vhosts/domain-one.com/node/app.js').app))
.use(express.vhost('domain-two.com', require('/var/www/vhosts/domain-two.com/node/app.js').app))
.listen(3030);
app.get('/', function(req, res){
res.send('hello world the server running ');
});
While in each app.js
var express = require('express'),
routes = require('./routes');
var app = exports.app = express.createServer();
app.get('/', function(req, res){
res.send('hello world test file for [domain-name] running');
});
//port 3031 for domain-one.com
//port 3032 for domain-two.com
app.listen(3031);
then i run node server.js and every thing works fine without errors.
then i run a netstat -anltp
tcp 0 0 0.0.0.0:3030 0.0.0.0:* LISTEN 19839/node
tcp 0 0 0.0.0.0:3031 0.0.0.0:* LISTEN 19839/node
tcp 0 0 0.0.0.0:3032 0.0.0.0:* LISTEN 19839/node
Ok everything goes as i expected (i suppose) so i open my browser and type domain-one.com:3031 and in other tab domain-two.com:3032
but drops a Connection time-out in both domains... and when i run domain-one.com:3030 it displays the:
hello world the server running
But not in domain-two.com:3030 it hangs also..
I, want to get my head around this and understand a bit about how my server and domains work and how to manage to run diferent nodejs apps for diferent ip/domains in my server...
somethimes the domain-two.com prints what the domain-one.com app.js file res.send() supposed to print on the other domain...
I guess im very confused now... hope you can help me out with this..
Thanks a lot
-ivan
Perhaps better with this simple and precise syntax:
https://github.com/expressjs/vhost
//
// Module dependencies
//
var express = require('express');
var vhost = require('vhost');
var app = express();
//
// vhosts
//
app
.use(vhost('app1.io', require('./app1/app.js')))
.use(vhost('app2.io', require('./app2/app.js')))
.use(vhost('app3.io', require('./app3/app.js')))
.listen(8080);

Categories

Resources