node httpServer EADDRINUSE and next port
Asked Answered
L

3

3

I try to increment a port number based on 8000 if the port is busy with EADDRINUSE, and I thought it's as easy as the below:

            var tryToOpenServer = function(port)
            {
              console.log('trying to Open: ' + port);

              HTTPserver
                .listen(port, function()
                {
                  console.log('HTTP listening:' + port);
                })
                .on('error', function(err)
                {
                  if (err.code === 'EADDRINUSE')
                  {
                    // port is currently in use
                    console.log('server Open error:' + port);

                    tryToOpenServer(port + 1);
                  }
                });

            };

            tryToOpenServer(8000);

If the port:8000 is busy and got err.code === 'EADDRINUSE', the port is incremented and the code tries the port. The problem is that

                .listen(port, function()
                {
                  console.log('HTTP listening:' + port);
                })

The above code somehow successfully runs on port:8000 even it throws an 'EADDRINUSE', so I've got 2 notifications: HTTP 8000 and 8001.

What do I miss? Please let me know thanks.

Lambkin answered 7/3, 2014 at 22:43 Comment(2)
Is this for development? are you sure you wouldn't rather killall node?Behl
It's like port scan. 8000 busy -> 8001 ...Lambkin
I
2

This is a Bad Idea.

Your recursion creates listeners exponentially.

If we modify your code at this Gist to track each listener that is created, we can see what happens. When I run the code and port 8000 is available, things are fine..

When 8000 is busy 8001 is available, I start to see multiple listeners..:

trying to Open: 8000
server Open error:8000
we have created 1 error event handler from 0
trying to Open: 8001
we have created 1 http server from caller 0
HTTP listening:8000
we have created 2 http server from caller 1
HTTP listening:8001

The first listener from trying port 8000 doesn't disappear.

Worse, the error listener doesn't disappear either. As more error listeners are created, every one fires on each error.

When I run your original code and both 8000 and 8001 are busy, I get these results with seven error event listeners and eight http listener functions created.

The fourth time, counts were in the 32k range and node was throwing warnings about leaks.

A better way, based on the code from Node's net documentation, might look like this. The single error handler can deal with the EADDRINUSE error each time it arises:

var http = require('http');
var port = 8000;
var HTTPserver = http.createServer(function (request, response) {
    response.writeHead(200);
    response.end("hello from server on port: " + port);
});
console.log('trying to Open: ' + port);
HTTPserver
  .listen(port, function () {
    console.log('we have created ' + listenerCounter + ' http server listeners');
    listenerCounter++;
    console.log('HTTP listening:' + port);
  })
  .on('error', function (err) {
    if (err.code === 'EADDRINUSE') {
      port++;
      console.log('Address in use, retrying on port ' + port);
      setTimeout(function () {
        HTTPserver.listen(port);
      }, 250);
    }
  });
Indigent answered 8/3, 2014 at 1:1 Comment(1)
Matt Bakaitis, thank you very much for your contribution for the testing and providing a sample code! I misunderstood that if the listener fails it's going to disappear, but actually not. I understood your detailed information. Looking at the nodeAPI docs, isn't it necessary to add serverInstance.close() for every on('error')?? In any case, I strongly agree with you that this is not a smart implementation, and I will go for port-scan preparation as another answer kindly suggested. Appreciated again!Lambkin
T
1

Make it easy and use portscanner

https://github.com/baalexander/node-portscanner

portscanner.findAPortNotInUse(8000, 9000, '127.0.0.1', function(error, port) {
     console.log('AVAILABLE PORT AT: ' + port)
})
Tchad answered 8/3, 2014 at 4:4 Comment(3)
Thanks a lot bryanmac! It seems this is the smartest way to implement. I'll do that.Lambkin
What didnt work? I use it in my project for what you're doing. Inside the findAPortNotInUser callback, I do server.list(port)Tchad
I am not sure, but it behaves in not straightforward way for my project. I have posted my own simple another solution here. Thanks anyway for your info.Lambkin
L
1

This works and is simple:

    var port = 8000;
    HTTPserver
      .listen(port, function()
      {
        console.log('HTTP listening:' + port);
      })
      .on('error', function(err)
      {
        if (err.code === 'EADDRINUSE')
        {
          // port is currently in use
          console.log('server Open error:' + port);

          port++;
          HTTPserver
            .listen(port);
        }
      });
Lambkin answered 8/3, 2014 at 8:17 Comment(2)
Seems like more code and less efficient than the port scanner.Tchad
That should not be true I think especially after I actually saw the code of the port scanner library.Lambkin

© 2022 - 2024 — McMap. All rights reserved.