Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

is it possible to make nodejs scripts listen to same port

Tags:

node.js

I ask the same question in another thread, but the answer misunderstood my question , thus I ask again

I have two scripts

 s1.js, s2.js

both use express framework and listen to certain port.

I call

node s1.js //listens to port 8080

node s2.js //listens to port 8081

to start the two scripts, one listens to port 8080, another listens to port 8081.

is it possible to make nodejs scripts listen to same port 8080? how to separate the two scripts when I call

www.abc.com:8080

Your comment welcome

Updated question

I try code app.js

  var express = require("express");
  var app = express();

  app.use('/app1', require( './app1/index.js').app);
  app.use('/app2', require( './app2/index.js').app);

  app.listen(8081);

in the path ./app1/index.js

  var express = require("express");
  var app = express();
  console.log("app1");
  app.listen(8081);

in the path ./app2/index.js

  var express = require("express");
  var app = express();
  console.log("app2");
  app.listen(8081);

then I called

  node app

console reports error:

app1

/Users/myname/node_modules/express/lib/application.js:111
  if (fn.handle && fn.set) app = fn;
        ^
TypeError: Cannot read property 'handle' of undefined
    at Function.app.use (/Users/zhengwang/node_modules/express/lib/application.js:111:9)
    at Object.<anonymous> (/Users/zhengwang/multi.js:27:7)
    at Module._compile (module.js:456:26)
    at Object.Module._extensions..js (module.js:474:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Function.Module.runMain (module.js:497:10)
    at startup (node.js:119:16)
    at node.js:901:3
like image 212
arachide Avatar asked Dec 06 '22 04:12

arachide


2 Answers

Cluster does this, and so does Express.vhost. You can in fact use both and only use 1 port all together.

// server.js
var cluster = require('cluster');
var express = require('express');
var app = express ();

var cpus = require('os').cpus().length - 1;

if(cluster.isMaster) {
    for(var i=0;i<cpus;i++) {
        cluster.fork ();
    }
}
else {
    app
        .use( express.vhost('www.site1.com'), require('./site1.js').app ) )
        .use( express.vhost('www.site2.com'), require('./site2.js').app ) )
        .listen(8080);
}

In the site1.js, site2.js, you write them out like you'd write any other node app, except for two little things. Export your app (var app = exports.app = express() ), and don't listen (app.listen(8080)) in those two files. You can see the server.js already does the listening for you, and also requires the two 'app' exports from them. Now all your sites on the same server can run on the same port, and on every CPU your server has. I do believe your server itself needs to be setup correctly too, for multiple vhosts, but that's beyond the question asked.

Cluster deals with sending requests to one of the node apps (server.js) running, then express deals with using the right app (site1.js, site2.js) for the request based on the url used. Surprisingly simple I'd say. I do love node.

like image 126
Chris Avatar answered Jan 11 '23 23:01

Chris


Okey, so here's the truth: multiple processes can listen on the same port. There are two cases known to me (only on POSIX):

1) Forking. When a master process listens on a socket and then it forks itself then all children listen on the same socket. This means that multiple processes listen on the same socket. And this actually what Node.js cluster does. You might want to have a look at it.

2) Passing socket file descriptor between two independent processes. Yes, it can be done. However there's a lots of work involved with it. Basically two processes communicate via UDS and one of them passes socket file descriptor to the other, so the other can listen on it as well. However this requires some low level network programming (passing a socket's FD is not as simple as passing it as a message). Here's an example of such implementation in C:

http://lists.canonical.org/pipermail/kragen-hacks/2002-January/000292.html

I'm not sure though whether 2) can be done with Node.js.

Note that in both cases it is up to OS to load balance between processes (it is OS that decides which process handles accept and/or recv on a socket). As far as I know most OS do their job really well.

However this is really impractical. I've never seen solution 2) used in real life (extremely complex, some serious security issues) and as for solution 1) it was widely used by (for example) Apache web server but nowadays people tend to use threads and/or async systems so forking becomes a bit obsolete (unless you want to take a full advantage of multiple CPU cores - there are no threads in Node.js).

So in your case I guess that the easiest solution would be to put a (ha)proxy in front of both servers so that it will load balance between these two scripts.

Note that the question is weird though. You say that you have two different servers but you want them to listen on the same port. This means that each request will go to one of them. In particular half users will be handled by s1 while the other half by s2. If they are doing the same that why are there two files? If they are doing something else then why would half of users get different result? It seems that you are trying to do something really bad.

like image 43
freakish Avatar answered Jan 12 '23 00:01

freakish