← Computer Networks
Networking Fundamentals

Ports & Sockets

Watch: "Running Out of TCP Ports" — Hussein Nasser

Every backend service you've ever deployed binds to a port, and every load test that mysteriously fails under high concurrency eventually traces back to socket or ephemeral port exhaustion. Understanding ports and sockets precisely is what separates "the server accepts connections" from actually knowing why — and it's a favorite interview topic because the naive mental model ("one port = one connection") is wrong in a way that trips up most candidates.

What Is a Port?

A port is a number, from 0 to 65,535, that tells a computer which specific program on it should receive incoming data. An address like an IP tells traffic which computer to go to; the port then tells that computer which running app — a web server, a game, an email client — should actually handle it.

What Is a Socket?

A socket is one specific, ongoing conversation between two programs over the network. It's more precise than just a port number — it's the full combination of both sides' addresses and ports, which is why a single port on a server can be involved in millions of separate conversations at once without them getting mixed up.

Where This Is Used

A Day-to-Day Example

Think of a large office building with one street address. The building's address gets mail to the right building (like an IP address), but each mail slot number — reception, accounting, HR — routes it to the right department inside (like a port). A socket is even more specific: it's like a particular phone call between a specific person in accounting and a specific customer, identified by both callers' numbers, so the switchboard can hold thousands of separate calls through the same main office line at once.

Deep Dive: The Socket 5-Tuple — Why One Port Can Serve Millions

Three connections to one server portclient A203.0.113.5 : 52001client B198.51.100.9 : 52001client A again203.0.113.5 : 52002server 10.0.0.20 : 4433 separate socketssocket = 5-tuple: protocol + src IP:port + dst IP:port
All three connect to port 443, yet the server keeps them apart because the full 5-tuple differs: a different source IP (A vs B) or a different source port (A's two connections). That is how one listening port serves millions of clients.
client Aclient B
Show text version
A TCP connection is uniquely identified by FIVE values, not one:

(protocol, source IP, source port, destination IP, destination port)

Client A: (TCP, 203.0.113.5, 52001, 10.0.0.20, 443)
Client B: (TCP, 198.51.100.9, 52001, 10.0.0.20, 443)   <- same dest port,
                                                            different src IP
Client A again: (TCP, 203.0.113.5, 52002, 10.0.0.20, 443) <- same src IP,
                                                                new src port

All three are DISTINCT sockets on the server, all listening on the same
port 443. The OS demultiplexes incoming packets using the full 5-tuple.

This is the single most important fact to internalize: a server "listening on port 443" is not a bottleneck of one connection per port. The listening socket just accepts new connections; each accepted connection becomes its own connected socket, and the 5-tuple — not the destination port alone — is what makes each one unique. A single server can hold millions of simultaneous connections on port 443 as long as it has file descriptors and memory to spare.

Deep Dive: The Port Number Ranges

Port number ranges drawn to scale0–10231024–49151 registered49152–65535well-known (root to bind): 80 HTTP, 443 HTTPS, 22 SSH, 53 DNSregistered: 3306 MySQL, 5432 Postgres, 6379 Redis, 27017 Mongoephemeral: picked by the OS for the client side of each connection
Drawn to scale: the well-known range is a sliver at the start. Servers listen on well-known or registered ports; clients get a random ephemeral port for every outgoing connection.
well-knownregisteredephemeral
Show text version
0     ─ 1023     Well-known / system ports (require root to bind on Unix)
                  80 HTTP, 443 HTTPS, 22 SSH, 53 DNS, 25 SMTP

1024  ─ 49151    Registered ports (app-specific, no root required)
                  3306 MySQL, 5432 PostgreSQL, 6379 Redis, 27017 MongoDB

49152 ─ 65535    Dynamic / private / ephemeral ports
                  the OS picks one of these automatically for the CLIENT
                  side of every outbound connection

On Linux the actual ephemeral range is often tuned to something like 32768–60999 (check /proc/sys/net/ipv4/ip_local_port_range) rather than the strict IANA 49152–65535 — worth knowing because that ~28,000-port pool is finite, and it's exactly what gets exhausted when a service opens huge numbers of short-lived outbound connections without pooling or reuse.

Key Pointers

How It Works

  1. A server process calls bind() on a specific port, then listen() to start accepting incoming TCP connections.
  2. A client calls connect(), which the OS pairs with an automatically assigned ephemeral local port.
  3. The server's accept() call returns a new socket, distinct from the listening socket, scoped to that one client connection.
  4. The OS uses the full 5-tuple (protocol, local IP/port, remote IP/port) to demultiplex incoming packets to the correct socket — this is how thousands of clients can connect to the same server port 443 simultaneously.
  5. When the connection closes, the socket is released, and — for TCP — enters a TIME_WAIT state briefly before the port can be reused for a new connection to the same remote endpoint.

Try It Yourself

# List all listening ports and their owning process:
lsof -i -P -n | grep LISTEN        # macOS/Linux
netstat -tulpn                     # Linux (needs sudo for process names)
ss -tulpn                          # modern Linux replacement for netstat

# Check if a specific host:port is reachable (no data sent, just the TCP handshake):
nc -zv example.com 443
nc -zv localhost 5432

# Count established connections by remote address (spot connection churn / leaks):
netstat -an | grep ESTABLISHED | awk '{print $5}' | sort | uniq -c | sort -rn

# See your ephemeral port range on Linux:
cat /proc/sys/net/ipv4/ip_local_port_range

# Watch TIME_WAIT sockets pile up (a sign of high connection churn):
netstat -an | grep TIME_WAIT | wc -l

Interview Q&A

Q: If a server listens on port 443, how can it handle a million concurrent clients through one port?

A: Because a TCP connection is identified by the full 5-tuple — protocol, local IP, local port, remote IP, remote port — not by the destination port alone. The listening socket on 443 just accepts new connections; each accepted connection becomes a distinct connected socket differentiated by the client's unique IP:port combination. The OS kernel demultiplexes incoming packets to the right socket using that full tuple, so the same local port 443 is shared across as many connections as the server has resources to hold open.

Q: What causes "ephemeral port exhaustion" and how do you fix it?

A: It happens when a process opens a very large number of short-lived outbound connections faster than the OS can recycle ephemeral ports — e.g. an API gateway making a fresh TCP connection per request to a downstream service instead of reusing connections. Each connection consumes an ephemeral port until it fully closes (including its TIME_WAIT period), so under high request rate the finite pool (~28K ports on Linux by default) runs dry, and new outbound connections start failing. The fix is connection pooling and HTTP keep-alive so the client reuses existing connections instead of opening a new socket per call; at scale, you can also add more source IPs, shrink TIME_WAIT (with care — see tcp_tw_reuse), or widen the ephemeral range.

Q: What's the difference between a port and a socket?

A: A port is just a 16-bit number — one piece of addressing info. A socket is the actual OS-level handle/object representing one endpoint of a specific connection, identified by the full 5-tuple (protocol + local IP/port + remote IP/port). Conflating them is the most common mistake: "the server has a socket open on port 443" is really shorthand for "the server has many sockets, all sharing local port 443 but each pinned to a different remote IP/port."

System Design Tie-in

In a "design a system that makes many downstream calls" interview (an API gateway, a BFF, a fan-out service calling dozens of microservices per request), the concrete failure mode to raise unprompted is ephemeral port and connection exhaustion on the calling side — solved with connection pooling, HTTP/1.1 keep-alive or HTTP/2 multiplexing (many logical requests over one TCP connection), and sizing pool limits against the downstream service's own capacity. It's also exactly why a load balancer or reverse proxy in front of a fleet of backend instances needs its own connection pool management to backend nodes, distinct from the client-facing connection count.

Trade-offs

A classic interview gotcha: "if a server listens on port 443, how can it handle a million concurrent clients through one port?" — the answer is that the 5-tuple, not the port alone, defines a connection, so the same local port can be shared across many distinct sockets differentiated by remote IP/port. Another practical pitfall: services that open a huge number of short-lived outbound connections (e.g. an API gateway calling many backends) can exhaust the ephemeral port range or pile up TIME_WAIT sockets, which is why connection pooling and keep-alive matter operationally, not just for latency.