Ports, sockets and the client-server model
What a port actually identifies, how ephemeral ports are assigned, what a listening and an accepted socket are, and the four-tuple that defines a connection.
A connection is a four-tuple
A port is not a channel; it is a demultiplexing key. The kernel identifies a connection by four values: source address, source port, destination address and destination port. Change any one and it is a different connection.
server listens on 0.0.0.0:443
connection 1 192.168.1.10:51001 -> 203.0.113.5:443
connection 2 192.168.1.10:51002 -> 203.0.113.5:443
connection 3 192.168.1.11:50000 -> 203.0.113.5:443
three distinct connections, one listening port| Port range | Name | Assigned by |
|---|---|---|
| 0-1023 | Well known | IANA; binding usually needs privilege or a capability |
| 1024-49151 | Registered | IANA registry; applications may use these |
| 49152-65535 | Dynamic or ephemeral | The operating system, for outgoing connections |
| 80 / 443 | HTTP / HTTPS | Web traffic |
| 22 / 25 / 53 | SSH / SMTP / DNS | Common infrastructure ports |
| 3306 / 5432 / 6379 | MySQL / PostgreSQL / Redis | Database defaults, often not exposed publicly |
Listening, accepting, connecting
import socket
# server: bind, listen, then accept repeatedly
srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
srv.bind(("0.0.0.0", 8080))
srv.listen(128) # backlog: pending connections the kernel queues
print("listening on", srv.getsockname())
conn, peer = srv.accept() # a NEW socket for this one connection
print("accepted from", peer)
conn.sendall(b"hello\n")
conn.close()
# client: each request gets a fresh ephemeral source port
c = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
c.connect(("127.0.0.1", 8080))
print("local side", c.getsockname()) # ('127.0.0.1', 51001) and similar
print(c.recv(1024))
c.close()- The listening socket itself carries no application data;
acceptreturns a new socket for each connection. - The backlog is finite. Once it fills, new TCP handshakes are dropped or refused, which is how a slow server causes client timeouts.
- An ephemeral port is held for a while after the connection closes, so rapid outbound connections can exhaust the range.
- Binding to a specific interface restricts which addresses accept traffic —
0.0.0.0means all of them.
Port exhaustion and its symptoms
# inspect sockets on Linux
ss -tlnp # listening TCP sockets with owning process
ss -tan state established | wc -l
ss -s # a summary including TIME-WAIT counts
# count ephemeral ports in use toward one destination
ss -tan | grep '203.0.113.5:443' | wc -l
# widen the ephemeral range if the workload is outbound-heavy
sysctl net.ipv4.ip_local_port_range| Symptom | Likely cause | Mitigation |
|---|---|---|
EADDRNOTAVAIL on connect | Ephemeral ports exhausted | Connection pooling, wider port range |
| Many sockets in TIME-WAIT | Short-lived outbound connections | Enable reuse, keep connections alive |
| Connections occasionally fail | Listen backlog overflowing | Raise the backlog, accept faster |
EADDRINUSE on restart | A socket is still bound | SO_REUSEADDR, or wait |
| Latency rises with concurrency | Accept queue delay, not bandwidth | Add workers, or offload to a proxy |
⚠️
A connection pool is the standard fix for outbound port exhaustion, but its size must be tuned. A pool of thousands per instance can exhaust the server's accept queue instead, which moves the failure rather than removing it.
FAQ
Can two services listen on the same port?
On the same address and protocol, no. Different address bindings, or TCP versus UDP, can coexist.
SO_REUSEPORT is an explicit exception used to spread load across processes.Why does a client source port matter?
It is what the server uses to tell concurrent connections apart. If two clients somehow used the same four-tuple, the kernel would treat them as one connection, which is why ephemeral ports are randomised.
Related
TCP in depth: handshake, windows and congestion control IP addressing, CIDR and subnetting
Last refreshed 2026-09-18.