Build the mental model
A port number is not a physical thing. There is no socket on the back of your machine numbered 443. A port is a 16-bit integer in the transport header whose only job is demultiplexing: one IP address arrives at one machine, but that machine runs many programs, and the kernel needs a key to decide which one gets these bytes. The port is that key. IP gets the data to the right host; the port gets it to the right process on that host.
IANA divides the 65,536 values into three ranges. Well-known ports, 0 to 1023, are for standard services and on Unix require privilege to bind, which is why web servers historically started as root just to claim port 80. Registered ports, 1024 to 49151, are assigned to specific applications on request. Ephemeral ports, 49152 to 65535, are the pool the kernel draws from when your side of a connection needs a temporary source port — you never choose these, and the range varies by operating system.
The point people miss is that a port does not identify a connection. The 4-tuple does: source IP, source port, destination IP, destination port. That is what the kernel hashes to route an arriving segment to the right socket. This is why a web server holds thousands of simultaneous connections on port 443 alone — every one of them shares the same destination IP and destination port, but each has a distinct source IP and source port, so no two tuples collide. The classic wrong mental model is "one connection uses up a port"; the real limit is unique tuples, and that space is vastly larger than 65,536.
THE 4-TUPLE: WHAT ACTUALLY IDENTIFIES A CONNECTION
--------------------------------------------------
( src IP , src port , dst IP , dst port )
| | | |
| | | +-- which service (443 = https)
| | +------------ which machine (the server)
| +---------------------- kernel-picked, per connection
+-------------------------------- which machine (the client)
Three clients, ONE listening port on the server:
203.0.113.7 :52001 ---+
|
203.0.113.7 :52002 ---+----> 198.51.100.10 : 443
| (one listening socket)
203.0.113.9 :52001 ---+
Server-side connection table:
src ip src port dst ip dst port conn
----------- -------- -------------- -------- ----
203.0.113.7 52001 198.51.100.10 443 #1
203.0.113.7 52002 198.51.100.10 443 #2
203.0.113.9 52001 198.51.100.10 443 #3
The right-hand columns are IDENTICAL on every row. The tuples
still differ, so the kernel never confuses one conn for another.
Port ranges (IANA):
0 - 1023 well-known privileged to bind on Unix
1024 - 49151 registered assigned on request
49152 - 65535 ephemeral kernel picks your source portConnect it to a real scenario
Consider a load balancer terminating 20,000 HTTPS connections. Every one of them has destination port 443 and the same destination IP, and none of them interfere with each other. Each arriving segment carries a source IP and source port, and the kernel looks up the full 4-tuple to find the right socket. The listening socket on 443 is a fifth thing entirely — it only accepts new connections; established ones live in their own entries and are matched by tuple, not by port.
Where the tuple does bite you is on the client side. A machine opening many outbound connections to the same destination is constrained by its ephemeral port range, because with source IP, destination IP, and destination port all fixed, the source port is the only field left to vary — roughly 28,000 concurrent connections on a default Linux range. This is exactly the "cannot assign requested address" error people hit during load testing, and the fixes follow directly from the tuple: widen the ephemeral range, add source IPs to vary another field, or reduce lingering TIME_WAIT sockets.
The code below builds several 4-tuples that share one destination, shows that they remain distinct, and classifies a handful of port numbers into the IANA ranges.
Try the working example
# IANA port ranges. No sockets are opened here -- this is pure arithmetic
# over numbers that the kernel would use as demultiplexing keys.
RANGES = (
(0, 1023, "well-known"),
(1024, 49151, "registered"),
(49152, 65535, "ephemeral"),
)
def classify(port):
if not 0 <= port <= 65535:
raise ValueError("a port is a 16-bit number: %d" % port)
for low, high, name in RANGES:
if low <= port <= high:
return name
def fmt(conn):
return "%s:%-5d -> %s:%d" % conn
# Four connections all arriving at the SAME server port.
connections = [
("203.0.113.7", 52001, "198.51.100.10", 443),
("203.0.113.7", 52002, "198.51.100.10", 443),
("203.0.113.9", 52001, "198.51.100.10", 443),
("203.0.113.9", 61000, "198.51.100.10", 443),
]
print("4-tuples seen by the server:")
for conn in connections:
print(" ", fmt(conn))
print()
print("distinct 4-tuples :", len(set(connections)))
print("distinct dst ip:port :", len({(c[2], c[3]) for c in connections}))
print("=> one listening port, four independent connections")
print()
print("%-8s %s" % ("port", "range"))
print("-" * 24)
for port in (22, 80, 443, 3000, 8080, 52001, 65535):
print("%-8d %s" % (port, classify(port)))
4-tuples seen by the server:
203.0.113.7:52001 -> 198.51.100.10:443
203.0.113.7:52002 -> 198.51.100.10:443
203.0.113.9:52001 -> 198.51.100.10:443
203.0.113.9:61000 -> 198.51.100.10:443
distinct 4-tuples : 4
distinct dst ip:port : 1
=> one listening port, four independent connections
port range
------------------------
22 well-known
80 well-known
443 well-known
3000 registered
8080 registered
52001 ephemeral
65535 ephemeral5-minute try-it
Add a second server to the connections list (for example one with destination port 80) and see how the distinct dst ip:port count changes. Then compute how many simultaneous connections one client can open to a single fixed destination using only the ephemeral range 49152-65535.
One important caution
Believing each connection consumes a port on the server — one server port carries thousands of connections; the real limits are distinct 4-tuples and file descriptors
Hard-coding the ephemeral range as 49152-65535 — the actual range is OS-specific (Linux defaults to 32768-60999), so classification and capacity math based on the IANA numbers can be wrong
IANA — Service Name and Transport Protocol Port Number Registry — Computer Networking