NodeJS and socket.io app on Heroku with 2 ports - node.js

My app has an express server listening on one port (process.env.PORT) and I also want a web socket using another port. I used to use Express 3 with this set-up:
var express = require('express'),
http = require('http'),
io = require('socket.io'),
app = express();
server = http.Server(app);
ioServer = io(server);
ioServer.on('connection', callback);
server.listen(process.env.PORT || 3000, function () {
console.log('App listening on ' + server.address().port);
});
The above code worked fine, as when creating ioServer, no specific port is required. However, after I switched to Express 4 and started using Heroku's WebSocket service, I had to specify a port like this:
var WebSocketServer = require('ws').Server,
port = 5000,
server = http.createServer(app);
server.listen(port);
var wss = new WebSocketServer({server: server});
wss.on('connection', callback);
app.listen(app.get('port'), function() {
console.log('Express server listening.'));
});
This new set-up never works because when I run the app on Heroku, I get an error complaining that the same port can't be used twice:
Error: listen EADDRINUSE :::40854
The set-up logic is essentially the same except for explicitly assigning a port in Express 4, so why did my code work with Express 3 but not Express 4? How should I fix this?

In your second code block, you can't call .listen() on both your server and on your app object. In this particular case (the way you've structured your code), you only want to call it on the server object, not on app.
This is the code from Heroku's dev page on this topic:
var WebSocketServer = require("ws").Server
var http = require("http")
var express = require("express")
var app = express()
var port = process.env.PORT || 5000
app.use(express.static(__dirname + "/"))
var server = http.createServer(app)
server.listen(port)
console.log("http server listening on %d", port)
var wss = new WebSocketServer({server: server})
console.log("websocket server created")
Also, your first code block is not running on two ports. As is usually the design for webSockets, a single port is used for both your web requests and your webSocket connections. The web server itself splits out the two types of connections based on the initial connection.

Related

Socket.io port configuration with Heroku

I'm trying to get socket.io working on my heorku app, but I think I'm having some trouble defining the ports. On the backend I have my express app listening to the process.env port or 5000, and I have my socket.io port listening on 8000.
Node.js
const express = require("express");
const app = express();
const server = require('http').Server(app)
const io = require('socket.io')(server)
const socketPort = 8000;
io.listen(socketPort);
const port = process.env.PORT || 5000;
app.listen(port, () => console.log(`Server running on port ${port} !`));
And on my front end I have my socket to route requests to localhost:8000
Reactjs
const socket = io('http://localhost:8000')
//Open connection to backend
socket.on('connect', ()=>{
console.log("Connected");
})
It works just fine when I run it locally, but I can't get it working on Heroku - GET http://localhost:8000/socket.io/?EIO=3&transport=polling&t=MszLUDm net::ERR_CONNECTION_REFUSED
Is there a specific way I need to set up these ports? As far as I know I can only set up one process.env port. Should I be subbing something into the "localhost:8000" on the front end?
Thanks!
On the client side I ended up just declaring the socket like this:
const socket = io();
Leaving out the localhost:5000 part altogether.

Connect to a heroku server with socket.io

How would one go about connecting to a heroku node.js server? For example, I have a server named 'https://example.herokuapp.com/' that uses node.js. How would I connect to it from a normal javascript file running socket.io. The code might look something like this:
var socket = io();
socket.connect('https://example.herokuapp.com/', { autoConnect: true});
I have tried this and I get the output of
polling-xhr.js:261 GET http://file/socket.io/?EIO=3&transport=polling&t=LjFlRl1 net::ERR_NAME_NOT_RESOLVED
So would I need an IP for the heroku server? If so how do I get it and is it even possible with heroku. If you're wondering why I don't host the html file on heroku it's because I'm using it for a website and my web host doesn't support node.js hosting. So I decided to host the node.js server on heroku. Thanks for your help in advance.
Server code:
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;
app.use(express.static(__dirname + '/public'));
server.listen(port, function () {
console.log('Server listening at port %d', port);
});
io.on('connection', function(socket){
console.log('connection' + socket.id)
socket.emit('ping', {
data: 'ping',
});
});

Socket.io with Express, how does express app know what port to listen on?

I am pretty new to nodejs and very new to socket.io and express. I have some code that is working, but am having trouble understanding exactly why it's working.
My question for the below code is how does the express app know to listen on port 80? There's a server.listen. But there is no app.listen in the code. Yet app.post() readily accepts posted data.
Please consider the following code
var https = require('https');
var url = require('url');
var fs = require('fs');
var bodyParser = require('body-parser');
var express = require('express');
var app = express();
//var io = require('socket.io');
var zlib = require('zlib');
app.use(bodyParser.urlencoded({extended: true }));
var options = {
key: fs.readFileSync('my.key'),
cert: fs.readFileSync('my.crt')
};
var serverPort = 80;
var server = https.createServer(options, app);
var io = require('socket.io')(server);
// log when the server is ready
server.listen(serverPort, function() {
console.log('Web socket server up and running at port %s', serverPort);
// this prints 80, as expected
});
app.post('/api', function (req, res) {
// working code is in here that receives the post variables and responds
}
With Express, the app object is just a request handler for some http server. If you call app.listen(), then the app object will create an http server for you. But, if you have created your own http server (which your code example does), then the app object just becomes a request listener on that server with this line of your code:
var server = https.createServer(options, app);
That creates the http server and registers app as a request listener (so it sees all incoming requests). This allows the Express app object to then process the routes that are registered with it to server routes like app.get(...) or app.post(...).
And, the port for Express is the port for the http server so it's the port that was used when the http server was created. What's important to understand here is that Express is not its own server. It's just a request listener for some http server.
In your code example, your http server is set up for port 80 so that's the port being used and Express gets registered as a request handler on all those incoming http requests on that port.
If you look at the source code for app.listen(), you see this:
app.listen = function listen() {
var server = http.createServer(this);
return server.listen.apply(server, arguments);
};
All, it does is create an http server with the app object as a listener and then call .listen() on that new server.
the app does not have to know on which port to listen. Basically, server is your HTTP server binding which listens on port 80 in your example. var server = https.createServer(options, app); then tells the server to listen on port 80 for HTTP requests and forward them to your app. The app then does the routing stuff that links the function you sepcified with app.post(...) to a specific request URL (/api in this case).
TL;DR: The app does not need to listen, because the server is the only communication interface to the outside.

Node.js, Start TCP server using express.js server

Can we start the TCP server using the port of express.js server, i know socket.io can do that using the following code
var express = require('express');
var app = express();
var server = app.listen(3000, function() {
console.log("server started on port 3000");
});
var io = require('socket.io').listen(server);

Deploying a website to windows azure with web sockets

I have a node.js project that works fine on my local machine running a node server. However when I deploy it to azure I can not connect to the websocket server. I heard somewhere that you may need to edit the web.config file to turn on web sockets, but I cant find that anywhere.
The server sets up a websocket like follows:
var http = require('http'),
port = process.env.port || 1337,
NodeSimpleRouter = require('node-simple-router'),
router = new NodeSimpleRouter(),
WebSocketServer = require('ws').Server,
wss = new WebSocketServer({port: 8080});
//create the server
http.createServer(router).listen(port);
console.log('Web server running on port ' + port);
and the client like this:
var socket = new WebSocket('ws://localhost:8080');
do I need to change any of these settings, such as the value of 'localhost'?
Azure can be a pain sometimes with websockets and node.js . Here is what I got to work using socket.io . I have my code deployed out as a cloud service. Be careful if you do VIP swaps from staging to prod because I have noticed it doesn't play nice with websockets.
app.set('port', process.env.PORT || 3000);
var server = http.createServer(app);
var io = require('socket.io').listen(server);
server.listen(app.get('port'));
//Chat room
io.sockets.on('connection', function (socket) {
socket.on('send', function (data) {
io.sockets.emit('message', data);
});
});
You can also override the websockets and force default of long-polling by using this:
//Over ride the Azure defaults
io.configure(function () {
io.set("transports", ["xhr-polling"]);
io.set("polling duration", 10);
});

Resources