Trouble getting free ports

I have integration test that starts several binaries, each of which is a web API that takes port number it should bind to via command-line arguments
So my test will first gather available ports like this

        let mut free_ports = {
            let mut ports = vec![];
            let mut sockets = vec![]; // just to make sure we won't pick the same port twice
            for _ in 0..(cfg.file_workers.len() + 2) {
                let socket = std::net::UdpSocket::bind("127.0.0.1:0").unwrap();
                let port = socket.local_addr().unwrap().port();
                sockets.push(socket);
                ports.push(port);
            }
            ports
        };

Where cfg.file_workers.len() + 2 is indeed the amount of ports that I need in total during the test.
But I have a problem: Sometimes, one of the components will panic and say that the port is already in use!
Firstly, I wonder if this is a TOCTOU problem (time of check to time of use) problem where there's actually another application grabbing the port in that tiny window of time? I kinda doubt it because it happens quite often, I mean what is the chance that some application grabs that exact (random) port in the timespan of a few milliseconds?

The next thing I tried was to start on port 40000 and for every component spawned, increment it.
Note that there are several tests and they all run in parallel. The port number variable is global across all tests, and the incrementing and reading of the port number variable is atomic, so surely each component has a separate port number.
It still fails sometimes. Interestingly, when running while true; do cargo test; done it has long sequences of success and then maybe a minute where for example port 40002 is taken.
I don't understand why some 400xx port is taken though.

syncthing    543 ploppz   17u  IPv6   28481      0t0  TCP *:22000 (LISTE )
syncthing    543 ploppz   18u  IPv4   28484      0t0  TCP 127.0.0.1:8384 (LISTEN)
spotify     4207 ploppz   86u  IPv4 1059487      0t0  TCP *:37147 (LISTE )
spotify     4207 ploppz   98u  IPv4   77338      0t0  TCP *:57621 (LISTE )
container  14113   root    8u  IPv4   98588      0t0  TCP 127.0.0.1:44009 (LISTEN)
docker-pr  68920   root    4u  IPv6  213909      0t0  TCP *:9000 (LISTEN)
docker-pr 175427   root    4u  IPv6  740622      0t0  TCP *:5432 (LISTEN)

Does anyone here have experience with the problem of selecting free ports for external applications?

Are your components also using 127.0.0.1? A free port from the code you posted won't necessarily be free on an address connected to a network.

Also, I wonder whether the Linux kernel (assuming that's what you're using) bothers to close UDP sockets synchronously, or if they could still be waiting for cleanup when you try to reuse them. That would make any code like this quite hard to get working.

I think they all use 127.0.0.1 yes.

But I think I just solved it, at least I'm having a hard time getting any port errors now.
I used ports 20000 and up instead. I guess 40000 and up are part of the "ephemeral ports" although Wikipedia states that the guideline for ephemeral ports is 49152 to 65535.

You can check the port number range that’s used for automatic allocation in /proc/sys/net/ipv4/ip_local_port_range. On the arbitrary Debian Docker image I tried, it’s ports 32768 to 60999.

I guess when you were using ports from this range with loopback connections, either by requesting port 0 or by starting from 40000, your application was using its own ports occasionally because client and server are using the same resources. Starting from 20000 is a good solution to that.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.