My company's product contains a web server. We don't bother to check to see if some other program is using port 80 or 443, we just use it. The reason is that we own the machine, we install the software, and we know there is nothing running on these ports; and more, if something is on these ports, we have no way to recover, so terminating abnormally is the right answer.
Picking a random port when you have been told to pick a specific port (even implicitly) makes no sense. What if I start flask telling it to use 8000 and it’s already taken by an other program I’m running (something I do semi-regularly as I run tests concurrently), just pick a random port unasked and notify no one about it?
"Listening on port $PORT. Warning: failed to bind localhost:5000. Start process with --port=$X to specify a different port"
That would be much more helpful behavior and messaging than simply failing, especially since it seems people don't know that they can control the port, and start looking to disabling OS services rather than changing a port...
But why this part? Python -m http.server tells me which port it is using or gives me "OSError: [Errno 48] Address already in use".
In fact, I just tried
python -m http.server $((10000 + RANDOM % 10000))
and it told me what port it started using.
Sockets cannot collide, therefore you cannot bind more than one service running on a host to the same socket, which means if both are using INADDR_ANY, they cannot use the same port. Nothing prevents you from having multiple IPs on a host, each bound by IP to the same port (which would be separate sockets).
For CLIENT applications, they aren't just utilizing sockets, they're utilizing connections, and a connection is a tuple of two sockets. You can have many many many connections utilizing the same port, as long as they don't collide exactly with the socket on the other side in their signature. There are various ways to handle this, but a typical one is that servers do a hand-off during connection initialization to a temporary port assigned to that connection.
So, Flask (a server), is saying you can't bind it to listen on a socket which is previously bound because it would cause a collision and violate the no-collision rule for sockets. But it doesn't in any way mean that port can't be overloaded by different sockets being bound to the same port.
> There are various ways to handle this, but a typical one is that servers do a hand-off during connection initialization to a temporary port assigned to that connection.
I don't think this is right. Servers don't normally use additional ports. Instead, a process can actually create multiple TCP (streaming) sockets with the same local address:local port combination, but different remote address:remote port combinations (each TCP socket is uniquely identified by a four-tuple).
The point though was that once Flask realizes that it can't bind the address:TCP socket, it shouldn't just give up without even telling users about other options.
It's not the only way to address this issue, but it is a common pattern for servers to do a TCP handoff to an ephemeral port during connection initialization. One of the reasons that this is done is because it allows you to have /multiple/ connections from the same client to the same server, which is useful for a number of reasons. You're correct that each TCP connection (which is two sockets, a socket is IP + port) four-tuple with a different remote IP or remote port is considered a separate identifiable entity, so in some cases that means the client is responsible for providing an ephemeral port that should be connected back on. It depends on a variety of factors. If neither side does this, then you are limited to a single connection for that protocol for a single client.
If you'd like to investigate some common servers that use connection handoff and ephemeral ports look at nginx and haproxy, both do this and can also suffer from ephemeral port exhaustion on heavily loaded servers because of it (there are mitigation strategies as well).