31

How can I check if port is busy for localhost?

Is there any standard algorithm? I am thinking at making a http request to that url and check if response status code is not 404.

2

5 Answers 5

39

You could attempt to start a server, either TCP or HTTP, it doesn't matter. Then you could try to start listening on a port, and if it fails, check if the error code is EADDRINUSE.

var net = require('net');
var server = net.createServer();

server.once('error', function(err) {
  if (err.code === 'EADDRINUSE') {
    // port is currently in use
  }
});

server.once('listening', function() {
  // close the server if listening doesn't fail
  server.close();
});

server.listen(/* put the port to check here */);

With the single-use event handlers, you could wrap this into an asynchronous check function.

4
  • 8
    This doesn't work with servers that aren't using SO_REUSEADDR. Check out github.com/baalexander/node-portscanner to see how they used net.Socket() to work around this. Commented Feb 19, 2014 at 15:47
  • 3
    you should also wait till the server closes... by listening to the server close event server.once('close', () => { myFunc() }).close()
    – Ray Foss
    Commented Oct 11, 2019 at 18:39
  • 1
    Launching a temporary server like this could lead to bad race conditions in multithreaded environments (e.g. Jest test-runner). Imagine if one thread launches a temporary server, while at the same time another thread tries to launch a "permanent" test-server. At this point, things could go haywire pretty fast.
    – Mike76
    Commented Nov 8, 2020 at 12:33
  • you need to make sure what ip is listen in cace you have multiple ips running
    – icinema gr
    Commented Dec 2, 2022 at 17:46
17

Check out the amazing tcp-port-used node module!

//Check if a port is open
tcpPortUsed.check(port [, host]) 

 //Wait until a port is no longer being used
tcpPortUsed.waitUntilFree(port [, retryTimeMs] [, timeOutMs])

//Wait until a port is accepting connections
tcpPortUsed.waitUntilUsed(port [, retryTimeMs] [, timeOutMs])

//and a few others!

I've used these to great effect with my gulp watch tasks for detecting when my Express server has been safely terminated and when it has spun up again.

This will accurately report whether a port is bound or not (regardless of SO_REUSEADDR and SO_REUSEPORT, as mentioned by @StevenVachon).

The portscanner NPM module will find free and used ports for you within ranges and is more useful if you're trying to find an open port to bind.

13
  • This solution caused a lot of trouble in my prod environment tcpPortUsed shows port as in use when listening port answer to telnet. I've a service accepting only one connection and refuse telnet. In such case it returns port is not in use. Commented Feb 11, 2021 at 7:05
  • 1
    @DavutGürbüz sorry to hear - can you explain? tcpPortUsed tries to make a TCP connection (not telnet - although telnet does the same thing) to the port. If it is able to make a connection, then the port is in use. If it is not, then the port is free. So I am not sure what you mean - a service can't know if a TCP connection is from telnet or from anything else until it accepts it.
    – Codebling
    Commented Feb 11, 2021 at 7:29
  • 1
    That's what I'm exactly talking about. In my TCP Server application I limited number of connection to 1. So, I guess this library is not able to establish the connection to the specified port and it thinks port is not in use. Commented Feb 11, 2021 at 7:33
  • Oh! I understand now. That's unfortunate. I suppose the better solution for you in this case is to simply try to open the port - although I believe that depending on how the port was opened, this also has an edge case
    – Codebling
    Commented Feb 11, 2021 at 7:37
  • If the port is opened with SO_REUSEPORT or SO_REUSEADDR then the port could be opened by more than one application - though it's unlikely that you have set this in your case. Just another edge case to consider
    – Codebling
    Commented Feb 11, 2021 at 7:40
5

Thank to Steven Vachon link, I made a simple example:

const net = require("net");
const Socket = net.Socket;

const getNextPort = async (port) =>
{
    return new Promise((resolve, reject) =>
    {
        const socket = new Socket();

        const timeout = () =>
        {
            resolve(port);
            socket.destroy();
        };

        const next = () =>
        {
            socket.destroy();
            resolve(getNextPort(++port));
        };

        setTimeout(timeout, 10);
        socket.on("timeout", timeout);

        socket.on("connect", () => next());

        socket.on("error", error =>
        {
            if (error.code !== "ECONNREFUSED")
                reject(error);
            else
                resolve(port);
        });

        socket.connect(port, "0.0.0.0");
    });
};

getNextPort(8080).then(port => {
    console.log("port", port);
});
9
  • Thnks, this works
    – ndotie
    Commented Jan 23, 2022 at 17:10
  • does this still work? I get all ports "ECONNREFUSED" but I'm able to start an http server on any of those ports. I'm on node 16.16.0
    – gman
    Commented Jul 20, 2022 at 17:49
  • I also had some issues, fixed it for myself and since you commented on it I'll now update it here as well ;)
    – Ido
    Commented Jul 20, 2022 at 18:51
  • I'm really confused. the new code works but do you mind explaining it? If the code gets error.code === ECONNREFUSED it resolves with the port???. If the code gets a connect the code calls next?
    – gman
    Commented Jul 20, 2022 at 19:01
  • 1
    I see my mis-understanding. I thought we were opening the port for listening. But we're not, we're trying to connect. Now it all makes sense. Thanks for putting up with me.
    – gman
    Commented Jul 20, 2022 at 22:20
2

this is what im doing, i hope it help someone


const isPortOpen = async (port: number): Promise<boolean> => {
    return new Promise((resolve, reject) => {
        let s = net.createServer();
        s.once('error', (err) => {
            s.close();
            if (err["code"] == "EADDRINUSE") {
                resolve(false);
            } else {
                resolve(false); // or throw error!!
                // reject(err); 
            }
        });
        s.once('listening', () => {
            resolve(true);
            s.close();
        });
        s.listen(port);
    });
}

const getNextOpenPort = async(startFrom: number = 2222) => {
    let openPort: number = null;
    while (startFrom < 65535 || !!openPort) {
        if (await isPortOpen(startFrom)) {
            openPort = startFrom;
            break;
        }
        startFrom++;
    }
    return openPort;
};


you can use isPortOpen if you just need to check if a port is busy or not. and the getNextOpenPort finds next open port after startFrom. for example :

let startSearchingFrom = 1024;
let port = await getNextOpenPort(startSearchingFrom);
console.log(port);
1
  • I think the name "isPortOpen" is not describing its purpose, maybe "isPortAvailable" suites better
    – gschaden
    Commented Apr 14, 2023 at 6:14
0

check without producing an error on mac and most unix/linux

const { spawnSync } = require('child_process')

function checkPort(port) {
  const output = spawnSync(
    `lsof -i tcp:${port} | awk '{print $2}' |grep --invert PID`,
    { shell: true }
  )
  if (output.error) {
    console.error(output.error)
    return
  }
  const pid = Buffer.from(output.stdout.buffer).toString().split('\n')[0]
  console.log({ pid })
  return pid
}

const pid = checkPort(443)
if (pid) {
  console.log(`the server is running, process id: ${pid}`)
}

Not the answer you're looking for? Browse other questions tagged or ask your own question.